preface

In the group chat, someone said that the interview asked about the implementation principle of async, and mentioned generator in the answer. Recently, I happened to learn the three things in the title, and felt that the answer was not appropriate, so I had a lot of trouble, and finally wrote the general logic of these three things by hand.

This article does not have the detailed source code analysis, belongs to the personal learning process of understanding, if you want to learn can refer to the link given in the article, if you have any comments/suggestions welcome to point out.

async

Here are the answers. The problem is that async functions are implemented in a way that I don’t think has anything to do with generators when I talk about async alone.

Let’s look at the description on MDN:

Async function defines an asynchronous function that returns an AsyncFunction object. An asynchronous function is a function that executes asynchronously through an event loop and returns its result with an implicit Promise.

Take a look at the conversion result on MDN:

For example, the following:

async function foo() {
   return1}Copy the code

is equivalent to:

function foo() {
   return Promise.resolve(1)
}
Copy the code

So the async implementation alone should be more like the following code:

function _async(fn) {
    return (. args) = > Promise.resolve(fn(... args)); }Copy the code

generator

Let’s see what a generator is. Generator is implemented first in order to be used in the following await. Here is the sample code from Liao Xuefeng’s tutorial:

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 the code

This can be understood as calling the next method on the “object” returned by the Generator and can produce a result similar to {value, done}.

Look at the dig friends write code like the 9 k Cai Xu pull out words | Promise/async/Generator principle analysis this article written by the Generator conversion results:

/ / 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 results
"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 the code

During the discussion in the group, 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 the result
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: 3, done: true }
// { value: 3, done: true }
Copy the code

The above code is certainly very different from the implementation in Babel and ES, but is basically a generator’s execution logic. For details, see switch (_context.prev = _context.next) and _context.next = 2; The code.

await

To review the use of await, it can transform asynchronous code into synchronous code logic, the application will be suspended until the asynchronous code return value arrives. So we’re going to pick a code that suspends the program, which is while(true). The implementation is as follows:

function _await() {
    let result = data.next();
    while (true) {
      console.log('waiting... ', result); 
      if (result.done) returnresult.value; result = data.next(); }}let g = get();
console.log('before');
let a = _await(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 the code

further

In practice, await can only be used in async, the group asks how to implement this, so the following version is created.

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) returnresult.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 the code

There is no other way to do this, except to use the control prototype to control whether it can be executed, but it can only be used inside async.

conclusion

This article is the understanding of personal learning process, if there is an understanding of the wrong place, welcome your advice. This article was written to add a different perspective to your code learning process.