Async function


The title content
The introduction of the async AsyncFunctionConstructor,Generator
The meaning of async What is async function?
The characteristics of the async Built-in actuators, better semantics, wider applicability, return value isPromise
The implementation principle of Async GeneratorFunction, the autoexecutor

The introduction of the async

  • The ES2017 standard was introducedasyncFunction to make asynchronous operations easier. Or you could sayGeneratorGrammar sugar.

AsyncFunction constructor

  • AsyncFunctionThe constructor is used to create a newAn asynchronous functionObject, every asynchronous function in JavaScriptAsyncFunctionThe object.
async function asyncFunction(){}
asyncFunction.constructor
// AsyncFunction() { [native code] }
Copy the code
  • Pay attention to: AsyncFunctionIt is not a global object and needs to be retrieved as follows:
Object.getPrototypeOf(async function(){}).constructor
// AsyncFunction() { [native code] }
Copy the code

AsyncFunction grammar

new AsyncFunction([arg1[, arg2[, ...argN]],] functionBody)
Copy the code

AsyncFunction parameters

  • arg1, arg2, … ArgN: The parameter names of the function, which are one or more comma-separated strings that conform to the JavaScript identifier specification. Such as x, theValue or a, b.

  • FunctionBody: A string of JavaScript statements that form the definition of a new function.

function resolveAfter2Seconds(x) {
  return new Promise(resolve= > {
    setTimeout(() = > {
      resolve(x);
    }, 2000);
  });
}

var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
var a = new AsyncFunction('a'.'b'.'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b); ');
a(10.20).then(v= > {
  console.log(v); Print 30 after 4 seconds
});
Copy the code
  • performAsyncFunctionConstructor, one is createdAn asynchronous functionObject. But it’s better to do it firstAsynchronous function expressionDefine an asynchronous function and then call it to create itAn asynchronous functionObjects come efficiently because in the second wayAsynchronous functions are parsed by the interpreter along with other codeAnd the first wayThe function body is parsed separately.
  • Passed to theAsyncFunctionconstructionalAll the parametersWill becomeA variable in a new function.Variables are named and defined in the same order as parameters.
  • Pay attention toUse:AsyncFunctionConstructorAn asynchronous functionWill not be inCreate closures in the current context, itsThe scope is always global. Therefore, it can only be accessed at runtimeTheir own local variablesandThe global variable, butCannot access a variable in the scope from which the constructor is called. That is with itevalDifferent places (evalFunctions are best never used.
/ * * *@description Own local and global variables */
function resolveAfter2Seconds(x) {
  return new Promise(resolve= > {
    setTimeout(() = > {
      resolve(x);
    }, 2000); })}var c = 1;
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;

var a = new AsyncFunction('a'.'b'.'c'.'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b) + await resolveAfter2Seconds(c); ');
a(10.20, c).then(v= > {
  console.log(v);
})
Copy the code
/ * * *@description Advice: Never use eval */
function test() {
  var x = 2, y = 4;
  console.log(eval('x + y'));  // Call directly, using local scope, resulting in 6
  var geval = eval; // equivalent to calling in global scope
  console.log(geval('x + y')); Throws ReferenceError because 'x' is not defined
  (0.eval) ('x + y'); // Another example of an indirect call
}
Copy the code
  • callAsyncFunctionConstructor can be omittednewThe effect is the same.

Async function

  • Async functions are usedasyncKeyword declaration function. Async functions are instances of the AsyncFunction constructor and are allowed in themawaitThe keyword.
  • The async and await keywords allow us to write based in a more concise wayPromiseAsynchronous behavior without the need for intentional chain callspromise.
function resolveAfter2Seconds() {
  return new Promise(resolve= > {
    setTimeout(() = > {
      resolve('resolved');
    }, 2000);
  });
}

async function asyncCall() {
  console.log('calling');
  const result = await resolveAfter2Seconds();
  console.log(result);
}

aysncCall();// Calling 2 seconds and resolved
Copy the code

Syntax of async functions

async function name([param[, param[, ... param]]]) {
  statements
}
Copy the code

Parameter of async function

  • name: Function name.
  • param: The name of the argument to be passed to the function.
  • statements: An expression containing the body of a function. You can useawaitMechanism.

The return value

  • aPromisethepromiseOr it will pass through aasyncThe value returned by the function is resolved, either by a value fromasyncAn exception thrown (or not caught) by a function is rejected.
async function foo() {
  return 1
}
/ / equivalent to the
function foo() {
  return Promise.resolve(1)}Copy the code
async function foo() {
  await 1
}
/ / equivalent to the
function foo() {
  return Promise.resolve(1).then(() = > undefined)}Copy the code

The meaning of async

  • The body of an async function can be thought of as being separated by zero or more await expressions. The first line of code up to (and including) the first await expression (if any) is run synchronously. In this case, an async function with no await expression will run synchronously. However, an async function must be executed asynchronously if the function body has an await expression.
// The promise chain is not built in one go. Instead, the promise chain is built in stages, so care must be taken with error functions when handling asynchronous functions
async function foo() {
  const result1 = await new Promise((resolve) = > setTimeout(() = > resolve('1')))
  const result2 = await new Promise((resolve) = > setTimeout(() = > resolve('2')))
}
foo()
Copy the code
  • The order of execution above:

    1. The first line of the foo function will be executed synchronously and await the end of the promise. It then suspends the process that passes through Foo and gives control back to the function that called foo.
    1. After a while, when the first promise ends, control reverts back to foo. The example will1(the promise state is fulfilled) is returned as the result to the left of the await expression, i.eresult1. The function will then continue, reaching the second await area, at which point the process of foo will be suspended again.
    1. And after a while, when the second promise ends,result2Will be assigned to2After that, the function will execute synchronously and will return by defaultundefined.
// A. Catch handler is configured on the Promise chain to throw unhandled Promise errors. This is because the result returned by P2 will not be processed with await
async function foo() {
  const p1 = new Promise((resolve) = > setTimeout(() = > resolve('1'), 1000))
  const p2 = new Promise((_,reject) = > setTimeout(() = > reject('2'), 500))
  const results = [await p1, await p2] // Not recommended. Use promise.all or promise.allSettled
}
foo().catch(() = > {}) // Catch all errors...
Copy the code
// Function declaration
async function foo() {};

// Function expression
const foo = async function () {};

// Object method
let obj = { async foo(){}}; obj.foo().then(...)// Class method
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars');
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`); }}const storage = new Storage();
storage.getAvatar('jack').then(...) ;// Arrow function
const foo = async() = > {};Copy the code

The characteristics of the async

Built-in actuator

  • Generator Function execution must depend on the executor, hence the existence ofcoModule, while async functionBuilt-in actuator. In other words, async functions are executed exactly like normal functions, with only one line.
const asyncFunction = async function () {
  const f1 = await 1
  const f2 = await 2
  console.log(f1.toString());
  console.log(f2.toString());
};

asyncFunction();
/ / 1
/ / 2
Copy the code
  • The above code callsasyncFunctionFunction, which will then automatically execute and output the final result. It doesn’t look like anythingGeneratorFunction, need to be callednextMethod, or usecoModule, can really execute, get the final result.
var gen = function* () {
  var f1 = yield 1
  var f2 = yield 2
  console.log(f1.toString())
  console.log(f2.toString())
}

var co = require('co'); // Generatir direct execution requires the CO module
co(gen).then(function() {
  console.log('Generator function completed execution ');
});
/ / 1
/ / 2
// The Generator function is complete
Copy the code

Better semantics

  • asyncandawaitCompared toThe asteriskandyieldThe semantics are clearer.asyncIt means that there are asynchronous operations in the function,awaitIndicates that the following expression needs to wait for the result.
const asyncFunction = async function() {
  const f1 = await 1 // The following expression waits for the result
  const f2 = await 2
  console.log(f1.toString())
  console.log(f2.toString())
}
Copy the code
const genFunction = function* () {
  const f1 = yield 1
  const f2 = yield 2
  console.log(f1.toString())
  console.log(f2.toString())
}
Copy the code

More practical type

  • coModule convention,yieldCommand can only be followed byThunk functionorPromise objectAnd theasyncFunction of theawaitAfter the command, it can bePromise objectandA value of the original type(The numerical,stringandBoolean value, but it will automatically change toImmediate Resolved Promise object).
Copy the code

The return value is Promise

  • asyncThe return value of the function isPromise objectThan theGeneratorThe return value of the function isIteratorObjects are much more convenient. You can usethenMethod specifies what to do next.
function getStockSymbol(name) {
  const symbolName = Symbol(name)
  return symbolName
}

function getStockUser(symbol) {
  return symbol
}

async function getUserByName(name) {
  const symbol = await getStockSymbol(name);
  const stockUser = await getStockUser(symbol);
  console.log('stockUser', stockUser)
  return stockUser;
}

getUserByName('JackDan').then(function (result) {
  console.log(result)
})
Copy the code
  • And going further,asyncFunctions can be thought of as multiple asynchronous operations wrapped into onePromise objectAnd theawaitThe command is the insidethenSyntax sugar for commands.
function timeout(ms) {
  return new Promise((resolve) = > {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms)
  console.log(value)
}

asyncPrint('hello world'.5000);
// Output hello world every 5 seconds
Copy the code
  • Due to theasyncThe function returns zeroPromiseObject that can be used asawaitCommand parameters.
async function timeout(ms) {
  await new Promise((resolve) = > {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world'.3000);
// Output hello world every 3 seconds
Copy the code

The implementation principle of Async

  • The implementation principle of async function is that the async function willGeneratorFunctions andautoactuator, wrapped in a function.
async function asyncFunction() {
  // ...
}

/ / is equivalent to

function asyncFunction(args) {
  return spawn(function* () {
    // ...})}function spawn(genFunction) {
  // Returns a Promise object. Async also returns a Promise object
  return new Promise(function(resolve, reject) {
    const _gen = genFunction();
    function step(nextFunction) {
      let _next;
      try {
        _next = nextFunction();
      } catch(e) {
        return reject(e);
      }
      if(_next.done) {
        return resolve(_next.value);
      }
      Promise.resolve(_next.value).then(function(v) {
        step(function() { return _gen.next(v); });
      }, function(e) {
        step(function() { return _gen.throw(e); });
      })
    }
    step(function() { return _gen.next(undefined); }); })}Copy the code

For a sample

var resolveAfter2Seconds = function () {
  console.log("starting slow promise");
  return new Promise((resolve) = > {
    setTimeout(function() { 
      resolve('slow');
      console.log("slow promise is done");
    }, 20000);
  });
};

var resolveAfter1Seconds = function () {
  console.log("starting fast promise");
  return new Promise((resolve) = > {
    setTimeout(function() {
      resolve('fast');
      console.log("fast promise is done");
    }, 1000);
  });
};

var parallel = async function() {
  console.log('==PARALLEL with await Promise.all==');
  
  await Promise.all([
    (async() = >console.log(await resolveAfter2Seconds()))(),
    (async() = >console.log(await resolveAfter1Seconds()))()
  ]);
}

setTimeout(parallel, 10000);
Copy the code
var resolveAfter2Seconds = function () {
  console.log("starting slow promise");
  return new Promise((resolve) = > {
    resolve('slow');
    console.log("slow promise is done")},2000);
}

var resolveAfter1Seconds = function () {
  console.log("starting fast promise");
  return new Promise((resolve) = > {
    resolve('fast');
    console.log("fast promise is done");
  }, 1000);
}

var sequentialStart = async function() {
  console.log('==SEQUENTIAL START==');

  // 1. Execution gets here almost instantly
  const slow = await resolveAfter2Seconds();
  console.log(slow); // 2. this runs 2 seconds after 1.

  const fast = await resolveAfter1Second();
  console.log(fast); // 3. this runs 3 seconds after 1.
}
Copy the code
var resolveAfter2Seconds = function () {
  console.log("starting slow promise");
  return new Promise((resolve) = > {
    resolve('slow');
    console.log("slow promise is done")},2000);
}

var resolveAfter1Seconds = function () {
  console.log("starting fast promise");
  return new Promise((resolve) = > {
    resolve('fast');
    console.log("fast promise is done");
  }, 1000);
}

var concurrentStart = async function() {
  console.log('==CONCURRENT START with await==');
  const slow = resolveAfter2Seconds(); // starts timer immediately
  const fast = resolveAfter1Second(); // starts timer immediately

  // 1. Execution gets here almost instantly
  console.log(await slow); // 2. this runs 2 seconds after 1.
  console.log(await fast); // 3. this runs 2 seconds after 1., immediately after 2., since fast is already resolved
}
Copy the code

JackDan Thinking

Developer.mozilla.org/zh-CN/docs/…

Developer.mozilla.org/zh-CN/docs/…