Async await

JavaScript Async/await (JavaScript异步/等待)

There exists a unique syntax that can enhance your performance with promises. It’s async/await: a surprisingly easy and comfortable means to deal with promises.

Async functions

Async functions (异步函数)

The async function declaration specifies an asynchronous function, which can return an AsyncFunction object. Async functions perform in a separate order than the rest of the code through the event loop and return a Promise as its result. Yet, the structure and the syntax of the code look similar to standard synchronous functions. (异步函数声明指定异步函数,该函数可以返回AsyncFunction对象。异步函数通过事件循环以与其他代码不同的顺序执行,并返回Promise作为其结果。然而,代码的结构和语法看起来与标准同步函数相似。)

As a rule, the keyword async is placed before a function, like here:

async function fn() {
 return 1;
}

Putting it before a function means that a function always returns a promise. (将其置于函数之前意味着函数始终返回一个promise。)

Let’s check out a case, where the function automatically returns a resolved promise with the result of 1:

async function fn() {
 return 1;
}
fn().then(console.log); // 1

You could explicitly return a promise that would be the same. Here is an example:

async function fn() {
 return Promise.resolve(1);
} 
fn().then(console.log); // 1

So, let’s assume that async returns a promise, wrapping non-promises in it. It can make your tasks much more manageable. Moreover, there exists another keyword, await, which works inside the async functions. (因此,让我们假设async返回一个promise ,在其中包装非promise。它可以使您的任务更容易管理。此外,还有另一个关键字await ,它在异步函数中起作用。)

Await

Await (v.等 ,期待,等待)

The await keyword makes JavaScript wait till the promise settles and returns the result. (Await关键字使JavaScript等待Promise解决并返回结果。)

The syntax looks like this:

//  only works inside async functions
let val = await promise;

Let’s explore an example with a promise resolving in a second:

async function fn() {
 let promise = new Promise((resolve, reject) => {
   setTimeout(() => resolve("Done!"), 1000)
(setTimeout (() = > resolve ("完成!"), 1000))
 });
 let res = await promise; // wait until the promise resolves (*)
 console.log(res); // result:  "Done!"
}
fn();

The function execution is suspended at the line () and resumed when the promise settles with res transforming into its result. So, in a second, the code shows “done”. (函数执行在行()处挂起,并在promise结算并res转换为其结果时恢复。一秒钟后,代码显示“完成”。)

await doesn’t cost any CPU resources, as the engine is capable of doing other jobs in the meantime. (await不消耗任何CPU资源,因为引擎同时能够执行其他作业。)

So, await can be considered a more elegant way to get the promise result than promise.then. (因此, await可以被认为是获得promise结果的一种比promise.then更优雅的方式。)

Note that you can’t use await in regular functions: a syntax error will occur.

For instance:

function fn() {
 let promise = Promise.resolve(1);
 let result = await promise; // Syntax error
}

The error, in the example above, will occur if you don’t put async before a function. So, await always works inside an async function. (在上面的示例中,如果不将async放在函数之前,就会发生错误。因此, await始终在异步函数内工作。)

Also, consider that await doesn’t operate in the top-level code. (此外,请考虑await在顶级代码中不起作用。)

See the following example:

// syntax error in top-level code
let response = await fetch('/promiseChaining/user.json');
let user = await response.json();

We can assume that the code above will not work. But, you have the option of wrapping it into an anonymous async function, as follows:

(async() => {
 let response = await fetch('/promiseChaining/user.json');
 let user = await response.json();
 ...
})();

await allows using thenable objects, like promise.then. (await允许使用thenable对象,如promise.then。)

Here the primary idea is that a third-party object might not be a promise, but promise-compatible, in case it supports .then, it’s enough for using with await. (这里的主要思想是,第三方对象可能不是promise ,而是promise-compatible ,如果它支持.then ,就足以与await一起使用。)

This is illustrated in the example below:

class Thenable {
 constructor(number) {
   this.number = number;
 }
 then(resolve, reject) {
  console.log(resolve);
   // resolve with this.num+2 after 2000ms
(//在2000ms后使用this.num+2解析)
   setTimeout(() => resolve(this.number + 2), 2000); // (*)
 }
};
async function fn() {
 // waits for 2 second, then result becomes 4
(//等待2秒,结果变为4)
 let result = await new Thenable(2);
 console.log(result);
}
fn();

In the event of getting a non-promise object with .then, await calls that method and provides the built-in functions resolve and reject as arguments. Afterward, await waits till one of them is called, then proceeds with the results. (如果使用.then获取非Promise对象,则await调用该方法并提供内置函数resolve和reject作为参数。之后,等待其中一个被调用,然后继续进行结果。)

If you want to declare an async class method, you should prepend it with async, as follows:

class  Supplier{
 async wait() {
   return await Promise.resolve(1);
 }
}
new Supplier()
 .wait()
(等等。)
 .then(console.log); // 1

The idea is the same: ensuring that the returned value is a promise and enabling await.

Error Handling

Error Handling (错误处理)

The await promise returns a result when a promise resolves typically. But, in the event of a rejection, it throws the error, just if it were a throw statement at that line. (AWAIT Promise通常在Promise解析时返回结果。 但是,在拒绝的情况下,它会抛出错误,只要它是该行的throw语句。)

The following two codes are equivalent:

async function fn() {
 await Promise.reject(new Error("Error!!"));
}
async function fn() {
 throw new Error("Error!!");
}

In real situations, the promise takes some time before the rejection. In such a case, there might be a delay before await throws an error. (在实际情况下,承诺需要一段时间才能被拒绝。在这种情况下,在await抛出错误之前可能会有延迟。)

It is possible to catch that error using try..catch like a regular throw. (可以像普通投掷一样使用try.. catch捕获该错误。)

One example is the following:

async function fn() {
 try {
   let response = await fetch('http://noSuchUrl');
 } catch (err) {
   console.log(err); // TypeError: failed to fetch
 }
}
fn();

If an error occurs, the control jumps to the catch block. You can also wrap multiple lines, like here:

async function fn() {
 try {
   let response = await fetch('/noUserHere');
   let user = await response.json();
 } catch (err) {
   // catches errors both in fetch and response.json
(//在fetch和response.json中捕获错误)
   console.log(err);
 }
}
fn();

In case, you don’t have try..catch, the promise created by the call of the async function fn() is rejected. So, .catch can be appended for handling it:

async function fn() {
 let response = await fetch('http://noSuchUrl');
}
// fn() becomes a rejected promise
fn().catch(console.log); // TypeError: failed to fetch (*)

Another important note: if you forget to add .catch, you will get an unhandled promise error. Such kinds of errors can be handled with unhandledrejection event handler. We have already explored it in the chapter Error handling with promises.

Async/await and promise.then/catch

Async/await and promise.then/catch (Async/await和promise.then/catch)

While using async/await, you may rarely need to apply .then, as await handles the waiting for you. Moreover, it is possible to use try..catch instead of .catch. Usually, it’s handier. (使用async/await时,您可能很少需要应用.then ,因为await会处理您的等待。此外,可以使用try.. catch代替.catch。通常,它更方便。)

But, as it was already mentioned, at the top level of the code, when you are outside any async function, you will syntactically not be able to use await. Hence, it’s a common practice to add .then/catch for handling the final result or falling-through an error, as in the line () of the case above. (但是,如前所述,在代码的顶层,当您在任何异步函数之外时,在语法上将无法使用await。因此,通常的做法是添加.then/catch来处理最终结果或处理错误,如上例中的行()所示。)

Use async/await to wait for a variable to be defined before continuing execution

Use async/await to wait for a variable to be defined before continuing execution (使用async/await等待定义变量,然后继续执行)

It is possible to use async/await to wait for a variable to be defined before continuing execution in JavaScript. Here’s an example:

function waitForVariable() {
 return new Promise((resolve) => {
   const intervalId = setInterval(() => {
     if (typeof myVariable !== "undefined") {
       clearInterval(intervalId);
       resolve();
     }
   }, 100);
 });
}

async function myFunction() {
 await waitForVariable();
 // Execution will continue here once myVariable is defined
(//定义myVariable后,此处将继续执行)
 console.log(myVariable);
}

let myVariable; // variable is undefined at this point

setTimeout(() => {
 myVariable = "Hello, world!"; // define myVariable after a delay
}, 2000);

myFunction(); // call myFunction

In this example, waitForVariable() returns a Promise that resolves when the myVariable variable is defined. The myFunction() function uses await to wait for this Promise to resolve before continuing execution. Once myVariable is defined, the function logs its value to the console. (在此示例中, waitForVariable ()返回一个Promise ,该Promise在定义myVariable变量时解析。myFunction ()函数使用await等待此Promise解析,然后继续执行。定义myVariable后,函数会将其值记录到控制台。)

Note that in this example, we’re using a setInterval function to periodically check whether myVariable has been defined yet. You could also use other methods to detect when the variable is defined, such as attaching an event listener or using a callback function. The key is to wrap the wait for the variable in a Promise that resolves when the variable is defined, and then use await to wait for the Promise to resolve before continuing execution. (请注意,在此示例中,我们使用setInterval函数定期检查myVariable是否已定义。还可以使用其他方法来检测何时定义变量,例如附加事件侦听器或使用回调函数。关键是将对变量的等待包装在Promise中,该Promise在定义变量时解析,然后使用await等待Promise解析,然后继续执行。)

Async/await and Promise.all

Async/await and Promise.all (Async/await和Promise.all)

Async/await, operates efficiently with Promise.all. (Async/await ,与Promise.all一起高效运行。)

For instance, when you need to wait for multiple promises, you can easily wrap then into Promise.all and then await, like here:

// wait for the array of results
let results = await Promise.all([
 fetch(urlOne),
(fetch (urlOne),)
 fetch(urlTwo),
(fetch (urlTwo),)
 ...
]);

If an error occurs, it propagates normally: from the failed promise to Promise.all, then becomes an exception, which you can catch implementing try..catch around the call.

Summary

Summary (概要)

In general, we can distinguish the following two effects of the async keyword:

Making it always return a promise. Allowing await to be used inside it. (让它始终返回一个承诺。 允许在里面使用await。)

The keyword await that is put before a promise makes JavaScript wait till the promise settles and then acts as follows:

In case an error occurs, the exception is generated: the same as if the throw error. In other cases, it will return the result.

Together async and await provide an excellent framework for writing asynchronous code, easy to write, and read. (Async和await一起为编写异步代码提供了一个出色的框架,易于编写和读取。)

Another prominent advantage: you will rarely need to write promise.then/catch with async/await. Also, Promise.all is there to help you whenever you are waiting for multiple tasks simultaneously.



请遵守《互联网环境法规》文明发言,欢迎讨论问题
扫码反馈

扫一扫,反馈当前页面

咨询反馈
扫码关注
返回顶部