当前位置:网站首页>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 .
边栏推荐
- C语言单向链表练习
- Small record of thinking
- 毕业设计项目
- 02 specific implementation of LS command
- C语言双向链表初版
- How to telecommute more efficiently | community essay solicitation
- Programmers' telecommuting is mixed | community essay solicitation
- 【微服务|openfeign】@FeignClient详解
- 2021 RSC | Drug–target affinity prediction using graph neural network and contact maps
- Spa in SDP
猜你喜欢
随机推荐
网络 - VXLAN
Leetcode skimming: binary tree 04 (sequence traversal of binary tree)
STM32外接DHT11显示温湿度
毕业设计:设计秒杀电商系统
NFT新的契机,多媒体NFT聚合平台OKALEIDO即将上线
Restore the subtlety of window position
NFT新的契机,多媒体NFT聚合平台OKALEIDO即将上线
Understand the principle of bytecode enhancement technology through the jvm-sandbox source code
Idea modify body color
JS realizes the effect of text scrolling marquee
Storage of MySQL database
分布式系统:what、why、how
96% of the collected traffic is prevented by bubble mart of cloud hosting
如何远程办公更有效率 | 社区征文
(指针)编写函数void fun(int x,int *pp,int *n)
C语言单向链表练习
微信脑力比拼答题小程序_支持流量主带最新题库文件
How to telecommute more efficiently | community essay solicitation
Leetcode skimming: binary tree 08 (maximum depth of n-ary tree)
01 qemu 启动编译好的镜像 VFS: Unable to mount root fs on unknown-block(0,0)