网上介绍async的文章有很多,但很多初学者在第一次接触时往往看得云里雾里。本文通过对一段代码执行过程的解析,希望能帮助到更多的萌新。话不多多,直接上代码
一、认识await的用法
function asyncTime(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 3000)
}
)
}
async function asyncTest() {
console.log("async-start");
let result = await asyncTime('hello world');
console.log(result);
return "我执行完啦"
}
console.log(start')
asyncTest()
console.log("eventloop");
1. 首先由于asyncTest()函数还未被调用,会先输出start
2.调用asyncTest(),此时打印async-start
3. 这一步是刚接触await时最难理解的一步。初学者受async里的代码会自上而下依次执行的用法影响,往往认为此时会先输出''hello world' 。但这里却先执行了最后一行‘eventloop‘’,最后再返回''hello world' 。这是为什么呢?
函数执行到await时,中断了async的执行。也就是说,此时asyncTest()函数的控制权移交给了asyncTime()。那这个asyncTime()是个啥呢?它内部返回的是一个promise对象。含义时:当经过3s的延时后promise的状态由pendding变为resolve。
控制权移交这个说法可能有点抽象,用一个更通俗的解释就是:此时代码运行的作用域(上下文)从asyncTest()这个函数跳到外面去了,而外面也就是window这个全局作用域。现在的问题就变成了在全局作用域下遇到了一个promsie对象,js线程会将它先挂入到一个等待队列,待本轮主线程的同步任务执行完后,再来执行这个promise对象。所以最后代码的执行顺序是start--async-start-eventloop-hello worold
二、await与promsie的关系
上述代码主要帮助大家理解await的作用,它会阻塞后面代码的运行,待 Promise 对象 resolve后得到 resolve 的值,作为 await 表达式的返回结果。这便是async强大的原因了,它将所有内部的异步操作都封装在了同一个Promise对象中,await可以看作是内部then的语法糖。这种写法的语义和适用性更好,内置的执行器也可以让async函数依次执行每一个await..。以下两个demo可以让你更深刻的理解await的作用
1. await后跟基本类型的数据
async function asyncNumber(){
console.log(await 1);
console.log(await 2);
}
asyncNumber()
console.log("start");
首先要明白,async本质是一个promise对象。所以即使await后跟的是基本类型,但仍是一个异步任务,需要等本轮同步任务执行完后才会依次执行await,所以输出结果是:start--1--2.
2. async里没有await
async function asyncNumber() {
console.log(1);
console.log(2);
}
asyncNumber()
console.log("start");
其实只要弄搞清楚async的本质后,这道题也迎刃而解。promsie有一个重要的特性:新建后立即执行。async里没有await,相当于promise里没有then。自然会立即执行,绝对不会阻塞后面的代码运行。
三、async的返回值
既然async的本质是一个promise,那必然可以通过then调用。而async里return的值将会被当作参数传递给then回调。如果没有return语句,参数会赋值为undefined。若async里写在return语句后的代码,自然也不会执行了(函数特性)
async function asyncNumber() {
console.log(1);
console.log(2);
return "这是我要传递的参数"
}
asyncNumber().then(res=>{console.log(res);})
console.log("start");
//1
//2
//start
//这是我要传递的参数
希望能通过以上几个demo,能帮助到一些入门者更加深刻的认识async。