1. Introduction
This article requires some knowledge of promises and generators
- Generators can be seen in my previous article on iterators and generators
2. Nature of async/await
Before, I only knew how to use async/await. I only knew that the code written after await is similar to that written in promise’s then, but I didn’t know what its internal nature is. Today finally understand the record
Async /await is essentially syntactic sugar for Generator and Promise
3. Use of async/await
function requestData(url) {
return new Promise((resolve, reject) = > {
setTimeout(() = > {
resolve(url)
}, 1000)})}async function foo() {
const res1 = await requestData('aaa')
const res2 = await requestData(res1 + 'bbb')
const res3 = await requestData(res2 + 'ccc')
console.log(res3)
}
foo()
Copy the code
Above we define a function foo that simulates asynchronous request data and call it with async await.
This code should print after 3 seconds
4. Use Generate function
If you think about the function foo above, Generate would look something like this
function* generatorFoo() {
const res1 = yield requestData('aaa')
const res2 = yield requestData(res1 + 'bbb')
const res3 = yield requestData(res2 + 'ccc')
console.log(res3)
}
generatorFoo()
Copy the code
But obviously the generator function above returns a generator, and it is impossible to execute the internal code without calling the next method, so how can we achieve the async/await result above?
So here it is
const generate = generatorFoo()
generate.next().value.then(res1= > {
generate.next(res1).value.then(res2= > {
generate.next(res2).value.then(res3= > {
generate.next(res3)
})
})
})
Copy the code
Explain the above code
Line 1: Calling the generator function returns a generator
Line 2: Call the next method to perform the first yield of generatorFoo, return the promise to the generator (in the generator’s value property), and then call the Promise’s then method to get the data for the requestData(‘ AAA ‘) asynchronous request
Line 3: Generator generate calls the next method to perform a second yield, but this time passes the data from the first request as an argument. The second yield execution also returns a promise to the generator (in the generator’s value property) and then calls the Promise’s then method to retrieve the data for the requestData(RES1 + ‘BBB ‘) asynchronous request
Line 4: Same as line 3
Call the next method to pass back the asynchronous request’s RES to perform the final console.log(res3)
5. In the end
The above code requires us to manually call the next method several times, but we can do some automatic encapsulation
function execGenerator(generatorFn) {
const generator = generatorFn()
function exec(res) {
const result = generator.next(res)
if(result.done) {
return result.value
}
result.value.then(res= > {
exec(res)
})
}
exec()
}
execGenerator(foo)
Copy the code
The above encapsulates an execGenerator automation function that receives a generator function
The logic is a recursive logic. Exec encapsulates a function exec in which the generator’s next method is executed. If the generator returns a value with the done attribute false, the exec function is recursively called. If the generator returns a value with the done attribute false, the exec function is recursively called.