preface
Some people in the group chatted that they asked about the implementation principle of async in the interview and mentioned generator in the answer. Recently, they just learned three things in the title. They felt that the answer was a bit inappropriate and they had some trouble. Finally, they wrote the general logic of these three things.
There is no detailed source code analysis in this article, which belongs to the way of understanding in the process of personal learning. If you want to learn, you can refer to the links given in this article. If you have any comments / suggestions, please point out.
async
Here are the answers from friends. The problem is the implementation principle of async function. When talking about async, I don't think it has anything to do with generator.
Let's take a look MDN Description on:
async function is used to define an asynchronous function that returns an AsyncFunction object. An asynchronous function is a function that is executed asynchronously through an event loop and returns its result through an implicit Promise.
Take a look MDN Conversion result on:
For example, the following:
async function foo() { return 1 } Copy code
is equivalent to:
function foo() { return Promise.resolve(1) } Copy code
So on the implementation of async, it should be more similar to the following code:
function _async(fn) { return (...args) => Promise.resolve(fn(...args)); } Copy code
generator
Let's see what the generator is. Generator is implemented first to be used in the following await. Here is Liao Xuefeng Example code in:
function* fib(max) { var t, a = 0, b = 1, n = 0; while (n < max) { yield a; [a, b] = [b, a + b]; n ++; } return; } var f = fib(5); f.next(); // {value: 0, done: false} f.next(); // {value: 1, done: false} f.next(); // {value: 1, done: false} f.next(); // {value: 2, done: false} f.next(); // {value: 3, done: false} f.next(); // {value: undefined, done: true} Copy code
It can be understood that calling the next method on the "object" returned by the generator can produce results similar to the form of {value, done}.
Let's take a look at digging friends Write code like Cai Xuhan Of 9k word | Promise/async/Generator implementation principle analysis The result of generator conversion written in this article:
// code function* foo() { yield 'result1' yield 'result2' yield 'result3' } const gen = foo() console.log(gen.next().value) console.log(gen.next().value) console.log(gen.next().value) // babel official website conversion result "use strict"; var _marked = /*#__PURE__*/ regeneratorRuntime.mark(foo); function foo() { return regeneratorRuntime.wrap(function foo$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; return 'result1'; case 2: _context.next = 4; return 'result2'; case 4: _context.next = 6; return 'result3'; case 6: case "end": return _context.stop(); } } }, _marked); } var gen = foo(); console.log(gen.next().value); console.log(gen.next().value); console.log(gen.next().value); Copy code
In the process of group discussion, in order to distinguish async from await, the following "generator" is written:
function get() { let g = { done: false, count: 0, next() { if (this.count === 3) this.done = true; if (this.done) return { value: this.count, done: this.done }; this.count++; return { value: this.count, done: this.done }; } } return g; } let obj = get(); console.log(obj.next()) console.log(obj.next()) console.log(obj.next()) console.log(obj.next()) console.log(obj.next()) // Output results // { value: 1, done: false } // { value: 2, done: false } // { value: 3, done: false } // { value: 3, done: true } // { value: 3, done: true } Copy code
The above code is quite different from the implementation in babel and ES, but it is basically the execution logic of a generator. For details, please refer to switch (_ context.prev = context.next )And a few lines_ context.next =2; code.
await
Let's review the function of await, which can transform asynchronous code into synchronous code logic. Before the return value of asynchronous code arrives, the program will be suspended. So we need to choose a code that can make the program hang, that is, while(true). The implementation is as follows:
function _await() { let result = data.next(); while (true) { console.log('waiting...', result); if (result.done) return result.value; result = data.next(); } } let g = get(); console.log('before'); let a = myAwait(g); console.log(a); console.log('after'); // output // before // awaiting... { value: 1, done: false } // awaiting... { value: 2, done: false } // awaiting... { value: 3, done: false } // awaiting... { value: 3, done: true } // 3 // after Copy code
further more
In the actual use process, await can only be used in async. The group friend asked how to implement this, so he tossed out the following version.
function myAwait() { this.c = function(data) { if (!this.isCalledByAsync) throw new Error('Should be called by async'); let result = data.next(); while (true) { console.log('awaiting...', result); if (result.done) return result.value; result = data.next(); } } } function myAsync(fn) { myAwait.prototype.isCalledByAsync = true; let m = get(); console.log('async before'); let d = new myAwait().c(m); console.log(d); console.log('async after'); myAwait.prototype.isCalledByAsync = false; } myAsync(); let g = get(); console.log('no async before'); let a = new myAwait().c(g); console.log(a); console.log('no async after'); // output // async before // awaiting... { value: 1, done: false } // awaiting... { value: 2, done: false } // awaiting... { value: 3, done: false } // awaiting... { value: 3, done: true } // 3 // async after // no async before // Error: Should be called by async Copy code
I didn't think of any other way to make this mark. I can only use the way of controlling the prototype to control whether it can be executed, but it can only be used inside async.
epilogue
This article is the understanding in the process of personal learning. If there is something wrong with the understanding, you are welcome to give advice. This article is also written for you to learn the code process to add some different perspectives.