当前位置:网站首页>Asynchronous development process - touch your hand and lead you to realize a promise
Asynchronous development process - touch your hand and lead you to realize a promise
2022-07-04 04:23:00 【Careteen】
Length is longer than the , But the key points are as follows , You can go directly to the topic of interest , each takes what he needs .
- Callback function
- analysis lodash Of after function
- analysis Node Read the file
- Why use promise
- Touch your hand and give you a hand promise
- Explain step by step from zero to one to achieve one promise
- Interview often takes an examination of , Please also read with questions .
- promise The relationship between the three states of ?
- How to achieve promise Chain call of ?
- How to judge and solve promise The problem of circular quotation ?
- How to achieve promise Of finally Method ?
- How to achieve promise Of all Method ?
- generator usage
- async-await
All the examples involved are stored in Warehouse , Interested students can directly clone Run locally .
This article mainly discusses the past and present life of asynchrony , And touch and take you to achieve a promise
because JavaScript Single thread features , We need asynchronous programming to solve the blocking problem .
Asynchronous programming problems
We may use the following functions to do some asynchronous operations in our daily work
- setTimeout
- onClick
- ajax
How to solve the asynchronous problem
The existing ways to solve the asynchronous problem are as follows
- Callback function
- promise
- generator nausea
- aync+await
Next, we will introduce various ways to solve the asynchronous problem one by one
Callback function
First, let's introduce higher-order functions , That is, the parameter of a function is a function or the return value of a function is a function , This function is called a higher-order function .
lodash-after function
Let's take another example , Regular use lodash Students should be familiar with a method _.after(n, fn), Role is fn Function is calling n It will be executed after times .
let fn = after(3, () => { console.log(' Time to execute ') }) fn() fn() fn() // => Time to execute
How to achieve a after
Function? , In fact, it's mainly the use of Closures and counts Thought :
const after = (times = 1, cb = _defaultCb) => { return function () { if (--times === 0) { cb() } } } const _defaultCb = () => {}
among cb
Pass in... As a function parameter after
function , It is an application of higher-order function .
after Function example address
Node Read the file
Now there's a scene , Read the contents of two files , Assign to an object , And print .
stay ./static Two new files are created under name.txt
,age.txt
, Expect to read the contents of the file and assign it to an object , And then print .
const fs = require('fs') let schoolInfo = {} fs.readFile('./static/name.txt', 'utf8', (err,data) => { schoolInfo['name'] = data }) fs.readFile('./static/age.txt', 'utf8', (err, data) => { schoolInfo['age'] = data }) console.log(schoolInfo) // {}
Because the process of reading files is asynchronous , Therefore, it is impossible to meet expectations in this way .
And asynchronous operation has the following three problems
- 1、 Asynchronous cannot catch errors
- 2、 Asynchronous programming , There may be a callback hell
- 3、 Multiple asynchronous operations , At the same time , How to synchronize asynchronous results ?
Everyone should be familiar with callback hell .
const fs = require('fs') let schoolInfo = {} fs.readFile('./static/name.txt', 'utf8', (err,data) => { schoolInfo['name'] = data fs.readFile('./static/age.txt', 'utf8', (err, data) => { schoolInfo['age'] = data }) })
And the reading time of the two files is cumulative , Not in parallel , If the files are many and large , The waiting time will be very long , So... Is not recommended .
Here is the third question Multiple asynchronous operations , At the same time , How to synchronize asynchronous results ?, May adopt Publish subscribe How to solve
// A simple way to subscribe to objects let dep = { arr: [], emit () { this.arr.forEach((fn) => { fn() }) }, on (fn) { this.arr.push(fn) } }
If you don't know the publish subscribe mode, please move to mine Another blog
The following operations can achieve the expectation
let schoolInfo = {} const fs = require('fs') // A simple way to subscribe to objects let dep = { arr: [], emit () { this.arr.forEach((fn) => { fn() }) }, on (fn) { this.arr.push(fn) } } // subscribe dep.on(() => { // �� Only after reading the contents of the two files and assigning values will it be printed if (Object.keys(schoolInfo).length === 2){ console.log(schoolInfo) } }) // Read trigger fs.readFile('./static/name.txt', 'utf8', (err, data) => { schoolInfo['name'] = data dep.emit() }) fs.readFile('./static/age.txt', 'utf8', (err, data) => { schoolInfo['age'] = data dep.emit() })
The print event is triggered every time the file is read , Judge in the event, and print only when both reads are completed .
The above method seems to solve the third problem mentioned above Multiple asynchronous operations , At the same time , The result of synchronous and asynchronous , But as demand changes , You need to read another address
file , The following changes are required :
... // subscribe dep.on(() => { // �� Only after reading the contents of the two files and assigning values will it be printed if (Object.keys(schoolInfo).length === 3){ // 2 Change it to 3 console.log(schoolInfo) } }) ... // Add a new item adress fs.readFile('./static/adress.txt', 'utf8', (err, data) => { schoolInfo['adress'] = data dep.emit() })
Add more items , The extensibility of the code is very poor .
How to implement a promise Then solve the problems mentioned above
node Read the file code address
Why use promise
Now, let's introduce promise The problem solved by the emergence of
- Back to hell , If multiple asynchronous requests , There is a joint and several relationship , Callback nesting
- If multiple asynchronous implementations are concurrent , There will be returned results that cannot be synchronized or asynchronously
- Error handling is inconvenient
promise usage
- Don't talk to you BB
Touch your hand and give you a hand promise
First of all, I need to mention promise/A+ standard , We wrote it ourselves promise It needs a standard . You can follow this standard step by step .
Three states are required
const PENDING = 'pending' // Waiting state const FULFILLED = 'fulfilled' // Success state const REJECTED = 'rejected' // Failure state
- When the state of
pending
when- May be converted to
fulfilled
orrejected
- May be converted to
- When the state of
fulfilled
orrejected
when- Cannot change to other state
- There has to be one
value
orreason
And it can't be changed
Interview point :promise The relationship between the three states of ?
then Method
For more details, please move to the document , Here are some key points
- Handle
executor
Abnormal code in function - Handle
executor
The code in the function is asynchronous - Handle then Multiple calls to
- Handle then Chain call of
Handle executor
Abnormal code in function
Yes executor
try-catch that will do
class Promise { constructor(executor) { let self = this self.status = PENDING self.value = undefined self.reason = undefined const resolve = (value) => { if(self.status === PENDING){ self.value = value self.status = FULFILLED } } const reject = (reason) => { if(self.status === PENDING){ self.reason = reason self.status = REJECTED } } try{ executor(resolve, reject) // If you do this executor An exception is thrown during execution We should go next then The failure of the }catch(e){ reject(e)// Something went wrong reason It's a mistake } } then (onFulfilled, onRejected) { if (this.status === FULFILLED){ onFulfilled(this.value) } if (this.status === REJECTED){ onRejected(this.reason) } } }
Use the following
let Promise = require('./3.1.promise.js') let p = new Promise((resolve,reject) => { resolve('xx') }) p.then((data) => { console.log('p success',data) }, (err) => { console.log(err) }) // => p success xx
Simple version of 1.0.0 Address as well as Test case address
Although a very simple promise, But there are still many problems , For example, below
let Promise = require('./3.1.promise.js') let p2 = new Promise((resolve,reject) => { setTimeout(() => { resolve('xxx') }, 1000) }) p2.then((data) => { console.log('p2 success',data) }, (err) => { console.log(err) }) // => p success xx // p second success xx
Asynchronous code will not be processed
Handle executor
The code in the function is asynchronous
Use the idea of publish subscribe mode to deal with
class Promise { constructor(executor) { let self = this self.status = PENDING self.value = undefined self.reason = undefined self.onResolvedCallbacks = [] // newly added An array is stored and processed successfully self.onRejectedCallbacks = [] // newly added Failed to store an array const resolve = (value) => { if(self.status === PENDING){ self.value = value self.status = FULFILLED self.onResolvedCallbacks.forEach((fn) => { // newly added When triggered, traverse all fn() }) } } const reject = (reason) => { if(self.status === PENDING){ self.reason = reason self.status = REJECTED self.onRejectedCallbacks.forEach((fn) => { // newly added When triggered, traverse all fn() }) } } try{ executor(resolve, reject) // If you do this executor An exception is thrown during execution We should go next then The failure of the }catch(e){ reject(e)// Something went wrong reason It's a mistake } } then (onFulfilled, onRejected) { if (this.status === FULFILLED){ onFulfilled(this.value) } if (this.status === REJECTED){ onRejected(this.reason) } if( this.status === PENDING){ // newly added Deal with asynchronous // Default current new Promise executor There is asynchronous in this.onResolvedCallbacks.push(() => { onFulfilled(this.value) }); this.onRejectedCallbacks.push(() => { onRejected(this.reason) }) } } }
Use
let Promise = require('./3.2.promise.js') let p = new Promise((resolve,reject) => { setTimeout(() => { resolve('xxx') }, 1000) }) p.then((data) => { console.log('p success',data) }, (err) => { console.log(err) }) p.then((data) => { console.log('p second success',data) }, (err) => { console.log(err) }) // Print in a second // => p success xxx // p second success xxx
Simple version of 1.0.1 Address as well as Test case address
Handle then Chain call of
and jQuery
Chain call a routine , But here we need to return a new promise
Not the present , Because the successful state and the failed state cannot be changed to other States
class Promise { constructor(executor) { let self = this self.status = PENDING self.value = undefined self.reason = undefined self.onResolvedCallbacks = [] self.onRejectedCallbacks = [] const resolve = (value) => { if(self.status === PENDING){ self.value = value self.status = FULFILLED self.onResolvedCallbacks.forEach((fn) => { fn() }) } } const reject = (reason) => { if(self.status === PENDING){ self.reason = reason self.status = REJECTED self.onRejectedCallbacks.forEach((fn) => { fn() }) } } try{ executor(resolve, reject) // If you do this executor An exception is thrown during execution We should go next then The failure of the }catch(e){ reject(e)// Something went wrong reason It's a mistake } } then (onFulfilled, onRejected) { let self = this let promise2 // This promise2 Every time we call then After returning to the new promise // This is the main way to realize chain call promise promise2 = new Promise((resolve, reject) => { if (self.status === FULFILLED) { setTimeout(() => { try { // This return value is the execution result of the successful function let x = onFulfilled(self.value) // Judge promise2 and x It's also then The result returned by the function is the same as promise2 The relationship between If x It's a normal value Then let's promise2 success If Is a failure promise Then let's promise2 Failure self._resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) } if (self.status === REJECTED) { setTimeout(() => { try { // This return value is the execution result of the failed function let x = onRejected(self.reason) // Judge promise2 and x It's also then The result returned by the function is the same as promise2 The relationship between If x It's a normal value Then let's promise2 success If Is a failure promise Then let's promise2 Failure self._resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) } if (self.status === PENDING) { // Default current new Promise executor There is asynchronous in self.onResolvedCallbacks.push(() => { setTimeout(() => { try { let x = onFulfilled(self.value) self._resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }); self.onRejectedCallbacks.push(() => { setTimeout(() => { try { let x = onRejected(self.reason) self._resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }, 0) }) } }) return promise2 } // Internal core method Handle The return value of successful or failed execution and promise2 The relationship between _resolvePromise (promise2, x, resolve, reject) { // This handler The logic that needs to be handled in Korean is very complex // It's possible that this x It's a promise But this promise It's not my own resolve(x) // At present, there is only one simple treatment } }
Use
let Promise = require('./3.3.promise.js') let p = new Promise((resolve,reject) => { setTimeout(() => { resolve('xxx') }, 1000) }) // promise in Every time you call then Should return a new promise // promise Instances of can only succeed or fail You can't succeed and fail p.then((data) => { console.log('p success', data) }, (err) => { console.log(err) }).then((data) => { console.log('success then', data) }, (err) => { console.log(err) }) // Print in a second // => p success xxx // success then undefined
Simple version of 1.0.2 Address as well as Test case address
Interview point : How to achieve promise Chain call of ?
For example, the code is only simple _resolvePromise
Method
perfect _resolvePromise
Step by step to standardize the document Handle _resolvePromise
The following situations need to be considered
_resolvePromise (promise2, x, resolve, reject)
- x Is a normal value
- x by promise2 Will cause a loop call
- x For an object or function
- x For one promise
Consider the above to improve
// Internal core method Handle The return value of successful or failed execution and promise2 The relationship between _resolvePromise (promise2, x, resolve, reject) { // This handler The logic that needs to be handled in Korean is very complex // It's possible that this x It's a promise But this promise It's not my own if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise ')) } // You don't just need to think about yourself Also need to consider It may be someone else's promise let called // Document requirements Once it's done Cannot call failed if ((x !== null && typeof x === 'object') || typeof x === 'function') { // This can only be said x It could be a promise try { // x = {then:function(){}} let then = x.then // take then Method if (typeof then === 'function') { then.call(x, y => { // resolve(new Promise) if (called) return called = true resolvePromise(promise2, y, resolve, reject) // Recursive check promise }, reason => { if (called) return called = true reject(reason) }) } else { // then Method does not exist resolve(x); // Common value } } catch (e) { // If you take then Method error , Just go and fail if (called) return called = true reject(e) } } else { // Common value resolve(x) } }
Use
let Promise = require('./3.4.promise.js') // Normal return value let p = new Promise((resolve,reject) => { setTimeout(() => { resolve('xxx') }, 1000) }) p.then((data) => { console.log(`p success ${data}`) return 'first result' }, (err) => { console.log(err) }).then((data) => { console.log(`p success then ${data}`) }, (err) => { console.log(`p error ${err}`) }) // Print in a second // => p success xxx // p success then first result // Throw the wrong let p2 = new Promise((resolve,reject) => { setTimeout(() => { resolve('p2 xxx') }, 1000) }) p2.then((data) => { throw new Error('just happy') }, (err) => { console.log(err) }).then((data) => { console.log(`p2 success then ${data}`) }, (err) => { console.log(`p2 error ${err}`) }) // Print in a second // => p2 error Error: just happy // promise let p3 = new Promise((resolve,reject) => { setTimeout(() => { resolve('p3 xxx') }, 1000) }) p3.then((data) => { return new Promise((resolve, reject) => { resolve('p3 data') }).then(data => { return data }) }, (err) => { console.log(err) }).then((data) => { console.log(`p3 success then ${data}`) }, (err) => { console.log(`p3 error ${err}`) }) // Circular reference - Examples to be changed let p4 = new Promise((resolve,reject) => { let circleP = new Promise((resolve, reject) => { resolve(circleP) }) return circleP }) p4.then((data) => { console.log(data) })
Simple version of 1.0.3 Address as well as Test case address
Interview point : How to judge and solve promise The problem of circular quotation ?
The above one conforms to Promise/A+
canonical promise Basically completed
How to verify what you wrote promise Is it right ?
Add the following deferred
Methods for inspection
// be based on Promise Realization Deferred Also available to `promises-aplus-tests` Checking static deferred () { let dfd = {} dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve dfd.reject = reject }) return dfd }
Install inspection tools promises-aplus-tests
npm i -g promises-aplus-tests
Execution check
promises-aplus-tests your-promise.js
All of them are green, which means they have passed the inspection
promise periphery
The above is just a simple promise, We expect to improve more functions :
- catch Method
- Static methods
- finally Method
- all Method
- race Method
The address of the following implementation is Simple version of 1.1.1 as well as The test case
catch Method
Realization
// be used for promise Method chain Capture the front onFulfilled/onRejected Exception thrown catch (onRejected) { return this.then(null, onRejected) }
Use
let Promise = require('./3.6.promise.js') // catch let p = new Promise((resolve,reject) => { setTimeout(() => { resolve('xxx') }, 1000) }) p.then((data) => { console.log(`p success then ${data}`) }).then((data) => { throw new Error('just happy') }).catch(err => { console.log(`p ${err}`) }) // => p success then xxx // p Error: just happy
Static methods
Realization
static resolve (value) { return new Promise(resolve => { resolve(value) }) } static reject (reason) { return new Promise((resolve, reject) => { reject(reason) }) }
Use
let Promise = require('./3.6.promise.js') // static resolve reject let p2 = Promise.resolve(100) p2.then(data => { console.log(`p2 ${data}`) }) let p3 = Promise.reject(999) p3.then(data => { console.log(`p3 ${data}`) }).catch(err => { console.log(`p3 err ${err}`) }) // => p2 100 // p3 err 999
finally Method
Realization
// finally It's also then A shorthand for finally (cb) { // Success or failure To perform all cb And pass the value of success or failure down return this.then(data => { cb() return data }, err => { cb() throw err }) }
Use
let Promise = require('./3.6.promise.js') // finally let p4 = Promise.resolve(100) p4.then(data => { throw new Error('error p4') }).finally(data => { console.log(`p4 ahhh`) }).catch(err => { console.log(`p4 err ${err}`) }) // => p4 ahhh // p4 err Error: error p4
Interview point : How to achieve promise Of finally Method ?
all Method
Realization
/** * @desc When everything in this array promise Objects all become resolve In state , Will resolve. * @param {Array<Promise>} promises promise An array of objects as parameters * @return Return to one Promise example */ static all (promises) { return new Promise((resolve, reject) => { let arr = [] // The way data is processed let i = 0 const processData = (index, data) => { arr[index] = data // The relationship between the index and length of the array if (++i === promises.length){ // When the length of the array and promise When the number of is equal Account for all promise It's all done resolve(arr) } } for (let i = 0; i < promises.length; i++){ let promise = promises[i] if (typeof promise.then == 'function'){ promise.then(function (data) { processData(i, data) // Index and data correspond Easy to use }, reject) }else{ processData(i,promise) } } }) }
Use
let Promise = require('./3.6.promise.js') // all & race const fs = require('fs') const path = require('path') const resolvePath = (file) => { return path.resolve(__dirname, '../callback/static/', file) } const read = (file) => { return new Promise((resolve, reject) => { fs.readFile(resolvePath(file), 'utf8', (err, data) => { if(err) reject(err) resolve(data) }) }) } // all Promise.all([ read('name.txt'), read('age.txt') ]).then(data => { console.log(`all ${data}`) }).catch(err => { console.log(`all err ${err}`) }) // => all Careteen,23
Interview point : How to achieve promise Of all Method ?
race Method
Realization
/** * @desc As long as there is one promise Objects enter FulFilled perhaps Rejected In terms of state , It will continue to be processed later ( It depends on which is faster ) * @param {Array<Promise>} promises receive promise An array of objects as parameters * @return Return to one Promise example */ static race (promises) { return new Promise((resolve, reject) => { promises.forEach((promise, index) => { promise.then(resolve, reject) }) }) }
Use
let Promise = require('./3.6.promise.js') // all & race const fs = require('fs') const path = require('path') const resolvePath = (file) => { return path.resolve(__dirname, '../callback/static/', file) } const read = (file) => { return new Promise((resolve, reject) => { fs.readFile(resolvePath(file), 'utf8', (err, data) => { if(err) reject(err) resolve(data) }) }) } // race Promise.race([ read('name.txt'), read('age.txt') ]).then(data => { console.log(`race ${data}`) }).catch(err => { console.log(`race err ${err}`) }) // => race Careteen/23 not always It depends on the reading speed
generator usage
Understanding generator Let's look at an example first .
Realize an addition function that can pass any parameter
The sum function can be obtained by dividing five by two
const sum = () => { return [...arguments].reduce((ret, item) => { return ret + item }, 0) } sum(1, 2, 3, 4) // => 10 sum(1, 2, 3, 4, 5) // => 15
Use ES6 The expansion operator of ...
All parameters can be listed , Then wrap it in an array , You can convert an array of classes into an array . utilize reduce To achieve accumulation , To get the summation function .
Can the expansion operator manipulate the class array pretended by the object ? Let's have a try
let obj = { 0: 1, 1: 2, 2: 3, length: 3 } console.log([...obj]) // => TypeError: obj[Symbol.iterator] is not a function
We can know that objects cannot be iterated , According to the error information , Let's improve the code
let o = { 0: 1, 1: 2, 2: 3, length: 3, [Symbol.iterator]: function () { let currentIndex = 0 let that = this return { next(){ return { value: that[currentIndex++], done: currentIndex-1 === that.length } } } }} let arr = [...o] // [1, 2, 3]
Reuse generator Realization
let o = {0: 1, 1: 2, 2: 3, length: 3, [Symbol.iterator]: function* () { let index = 0 while (index !== this.length) { yield this[index] index++ } } } let arr = [...o] // [1, 2, 3]
Generator can realize generation iterator , Generator function is to add a * Combined with yield To use , also yield It has pause function .
function * say() { yield 'node' yield 'react' yield 'vue' }
How to traverse iterators ?
let it = say () let flag = false do{ let {value, done} = it.next() console.log(value) flag = done }while(!flag) // => node // react // vue // undefined
Iterators provide next
Method , Iterative value
And whether the iteration has been completed done
, You can traverse with one loop .
yield The use scenario of the return value of
function * say() { let a = yield 'hello' console.log('a', a) let b = yield 'careteen' console.log('b', b) let c = yield 'lanlan' console.log(c) } let it = say() it.next(100) // for the first time next Pass parameters It's meaningless it.next(200) it.next(300) // => a 200 // b 300
generator The execution process is generally shown in the figure below
You can see for the first time next Passing parameters is meaningless , So the output is a 200 b 300
All of the above are synchronous , So let's see yield The following is the asynchronous scenario .
Let's take another example to further understand .
By reading the file 1.txt
The content is 2.txt
, Read again 2.txt
The content is 3.txt
, Last read 3.txt
The content in Careteen
First, you need to prepare three files , Put in ./static
Under the table of contents , Then prepare the function to read the file ,
const fs = require('fs') const path = require('path') const resolvePath = (file) => { return path.resolve(__dirname, './static/', file) } function read (file) { return new Promise((resolve, reject) => { fs.readFile(resolvePath(file), 'utf8', (err, data) => { if (err) reject(err) resolve(data) }) }) }
In the use of generator Implement the read function
function * r() { let r1 = yield read('1.txt') let r2 = yield read(r1) let r3 = yield read(r2) return r3 }
The desired process is by reading the file 1.txt
The content is 2.txt
, Read again 2.txt
The content is 3.txt
, Last read 3.txt
The content in Careteen
, Go back .
First of all, we can think of using callback to solve , because yield There's a promise
let it = r() let {value,done} = it.next() value.then((data) => { // data->2.txt let {value,done} = it.next(data) value.then((data) => { let { value, done } = it.next(data) value.then((data) => { console.log(data) // data-> result }) }) }) // => Careteen
But this will create a callback hell , So we need to optimize , We need an iterative function , Recursion can achieve
function co (it) { return new Promise((resolve, reject) => { // next Method express koa principle It's all like this function next (data) { // Use iterative functions to implement Asynchronous operations are performed sequentially let { value, done } = it.next(data) if(done){ resolve(value) }else{ value.then((data) => { next(data) },reject) } } next() }) }
So that asynchrony can be executed in sequence , Finally, let's take a look at the implementation
co(r()).then((data) => { console.log(data) }) // => Careteen
It is perfectly realized , But if yield After is a synchronization operation , No, then Method , stay co
We also need special treatment in the method , It's easier .
Fucking great TJ The great god CO The library handles this perfectly , Interested can go to the warehouse to see the source code , Only 200 Multiple lines .
generator Application :
How to achieve generator
function * careteen() { yield 100 yield 200 }
You can see babel Compiled results
async-await
- It's synchronous , Grammar sugar is sweet but not greasy .
- bluebird
- promisify
- promisifyAll
- async-await
- Serial condition
- Parallel situation
- async-await Internal mechanism
- stay babel Compile results in , In essence generator+co
- Example
- Three small balls roll
- Callback implementation Back to hell
- promise Realization It's not very beautiful either
- generator Realization need co library
- async-await Realization
- Three small balls roll
async function careteen() { await 100 await 200 return 300 } careteen.then(_ => { console.log(_) })
adopt babel After compiling It can be seen that it is essentially through generator+co
The way to achieve .
边栏推荐
- 干货!基于GAN的稀有样本生成
- Balance between picture performance of unity mobile game performance optimization spectrum and GPU pressure
- What does software testing do? Find defects and improve the quality of software
- Common methods of threads
- Distributed system: what, why, how
- One click compilation and deployment of MySQL
- 【读书会第十三期】多媒体处理工具 FFmpeg 工具集
- R语言中如何查看已安装的R包
- leetcode刷题:二叉树04(二叉树的层序遍历)
- Pointer array and array pointer
猜你喜欢
The difference between bagging and boosting in machine learning
一个漂亮的API文档生成工具
北漂程序员,月薪20K,一年攒15W,正常吗?
普源DS1000Z系列数字示波器在通信原理实验中的应用方案
指针数组和数组指针
三年进账35.31亿,这个江西老表要IPO了
The maximum expiration time of client secret in azure ad application registration is modified to 2 years
Pointer array and array pointer
R语言中如何查看已安装的R包
leetcode刷题:二叉树05(翻转二叉树)
随机推荐
Pointer array and array pointer
laravel admin里百度编辑器自定义路径和文件名
Rhcsa-- day one
Flink learning 8: data consistency
Two commonly used graphics can easily realize data display
Tcp- simple understanding of three handshakes and four waves
RHCSA 03 - 文件的基础权限
User defined path and file name of Baidu editor in laravel admin
I was tortured by my colleague's null pointer for a long time, and finally learned how to deal with null pointer
Redis:哈希hash类型数据操作命令
Evolution of MySQL database architecture
程序员远程办公喜忧参半| 社区征文
How to dynamically cache components in Vue multi-level route nesting
微信脑力比拼答题小程序_支持流量主带最新题库文件
C语言双向链表初版
STM32外接DHT11显示温湿度
【读书会第十三期】多媒体处理工具 FFmpeg 工具集
Ppt tutorial, how to save a presentation as a PDF file in PowerPoint?
idea修改主体颜色
【webrtc】m98 ninja 构建和编译指令