background
Recently, I contacted a UMI project, in which DVA is used for state management. Then you find generator syntax for JS. Although I’ve worked with generators in other languages (Python, PHP) before, I know what they do. But for asynchronous programming in JS synchronous writing method is not quite clear behind the principle, so studied.
process
First we define an asynchronous method to get the data, call it and return a Promise object, then we do not use async/await, use generator to copy DVA writing and write synchronous code to get the data.
const fetchData = () = > new Promise(resolve= > {
setTimeout(() = > {
resolve('test data')},3000)})function *test(call) {
const res = yield call(fetchData)
console.log(res)
}
Copy the code
We know that once we call generator’s next method, the program goes one step further. So how do we write the call parameter so that we can call next when appropriate?
I came up with my own idea here
const call = p= > {
p.then(res= > {
g.next(res)
})
}
g = test(call)
g.next()
Copy the code
The final code, plus the log print, looks at the order of execution:
const fetchData = () = > new Promise(resolve= > {
setTimeout(() = > {
resolve('test data')},3000)})function *test(call) {
console.log(2)
const res = yield call(fetchData())
console.log(res)
}
const call = p= > {
console.log(3)
p.then(res= > {
console.log(4)
g.next(res);
console.log(5)});console.log(6)}console.log(-1)
g = test(call)
console.log(0)
g.next()
console.log(1)
Copy the code
The execution result
-1
0
2
3
6
1
4
test data
5
Copy the code
This allows us to emulate async/await using generator.
further
Here we pass a call again, which is ugly and can only execute a single yield generator. So revamp it a bit and introduce a run method that uses recursion to automatically go down, like this:
const fetchData = (arg) = > new Promise(resolve= > {
setTimeout(() = > {
resolve('test data ' + arg)
}, 3000)})function *test() {
console.log('0')
let res = yield fetchData('1')
console.log('1', res)
res = yield fetchData(res)
console.log('2', res)
res = yield fetchData(res)
console.log('3', res)
res = yield fetchData(res)
console.log('4', res)
}
const run = g= > {
const next = val= > {
const res = g.next(val)
if(res.done) return res.value
res.value.then(next)
}
next()
}
run(test())
Copy the code
The execution result
0
1 test data 1
2 test data test data 1
3 test data test data test data 1
4 test data test data test data test data 1
Copy the code
reference
- Developer.mozilla.org/zh-CN/docs/…