您的位置:首页 > Web前端 > JavaScript

JavaScript 的 async/await 执行顺序详解

2020-07-18 05:25 736 查看

async/await 执行顺序详解

JavaScript 中的 async/await 是 AsyncFunction 特性 中的关键字,从字面意思来理解:async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。

先简单介绍一下async/await。

  • async/await 是一种编写异步代码的新方法。之前异步代码的方案是回调和 promise。
  • async/await 是建立在 promise 的基础上
  • async/await 像 promise 一样,也是非阻塞的。
  • async/await 让异步代码看起来、表现起来更像同步代码。

另外还有一个很有意思的语法规定,await 只能出现在 async 函数中。然后细心的朋友会产生一个疑问,如果 await 只能出现在 async 函数中,那这个 async 函数应该怎么调用?

1.async怎么处理返回值

async function testAsync() {
return "hello async";
}
const result = testAsync();
console.log(result);

输出结果: Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "hello async"}

可以看出:async 函数返回的是一个 Promise 对象。 如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。

如果没有返回值:

async function testAsync1() {
console.log("hello async");
}
let result1 = testAsync1();
console.log(result1);

输出结果: Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}

结果返回Promise.resolve(undefined)。

所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。

那么下一个关键点就在于 await 关键字了。

2. await 等待的机制

一般来说,都认为 await 是在等待一个 async 函数完成。准确说,await 等待的是一个表达式,这个表达式的 是 Promise 对象或者其它值 。

因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值——这也可以说是 await 在等 async 函数,但要清楚,它等的实际是一个返回值 ,await 后面实际是可以接普通函数调用或者直接量的。

await 等到了它要等的东西,一个 Promise 对象,或者其它值,然后呢?await 是个运算符,用于组成表达式,await 表达式的运算结果取决于它等的东西。

如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。

如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。这就是 await 必须用在 async 函数中的原因。async 函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个 Promise 对象中异步执行。
看一个简单的例子:

function testSome () {
console.log("执行testSome ");
return "testSome ";
}

async function testAsync() {
console.log("执行testAsync");
return Promise.resolve("hello async");
}

async function test() {
console.log("test start...");
const v1 = await testSome();  //关键点1
console.log(v1);
const v2 = await testAsync();
console.log(v2);
}

test();
var promise = new Promise((resolve)=> {
console.log("promise start..");
resolve("promise");   //关键点2
});promise.then((val)=> console.log(val));

console.log("test end...")

输出结果:

test start...
执行testSome
promise start..
test end...
testSome
执行testAsync
promise
hello async

执行顺序

  • 1.当test函数执行到
const v1 = await testSometing();

会先执行testSome这个函数,打印出“执行testSome”的字符串

  • 2.然后因为await会让出线程就会区执行后面的
var promise = new Promise((resolve)=> {
console.log("promise start..");
resolve("promise");   //关键点2
});

然后打印出“promise start…”接下来会把返回的这promise放入promise队列,

  • 3.继续执行打印
test  end...,
  • 4.本轮事件循环执行结束后,又会跳回到async函数中(test函数),等待之前await 后面表达式的返回值,因为testSome不是async函数,所以返回的是一个字符串
testSome
  • 5.test函数继续执行,执行到 const v2 = await testAsync(),和之前一样会输出
执行testAsync
  • 6.然后跳出test函数,执行后续代码,此时事件循环就到了promise的队列,执行promise.then里面的语句,打印
promise
  • 7.之后又跳回到test函数继续执行。
hello async

这个就是在async/await 函数之后js的执行顺序

3.async/await 优势

来一个例子比较一下then()链和async/awai:

执行三个步骤,每一个步骤都需要之前步骤的结果。

function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}

function step2(m, n) {
console.log(`step2 with ${m} and ${n}`);
return takeLongTime(m + n);
}

function step3(k, m, n) {
console.log(`step3 with ${k}, ${m} and ${n}`);
return takeLongTime(k + m + n);
}

1.先用 .then()的方法

function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => {
return step2(time1, time2)
.then(time3 => [time1, time2, time3]);
})
.then(times => {
const [time1, time2, time3] = times;
return step3(time1, time2, time3);
})
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}

doIt();

看起来就非常复杂!一堆的参数处理,还非常容易在逻辑上出错。

2.用 async/await 来写:

async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time1, time2);
const result = await step3(time1, time2, time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}

doIt();

这样逻辑就非常清晰了,浅显易懂,还便于维护!

借鉴博客:https://www.cnblogs.com/lpggo/p/8127604.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: