随着async/await
正式纳入ES7
标准,越来越多的人开始研究据说是异步编程终级解决方案的 async/await
。但是很多人对这个方法中内部怎么执行的还不是很了解,本文是我看了一遍技术博客理解 JavaScript
的 async/await
(如果对async/await
不熟悉可以先看下这篇文章)后拓展了一下,我理了一下await
之后js的执行顺序,希望可以给别人解疑答惑,先简单介绍一下async/await
。
async/await
是一种编写异步代码的新方法。之前异步代码的方案是回调和 promise。async/await
是建立在 promise 的基础上。async/await
像 promise
一样,也是非阻塞的。async/await
让异步代码看起来、表现起来更像同步代码。这正是其威力所在。async
怎么处理返回值
async function testAsync() {
return "hello async";
}
let result = testAsync();
console.log(result)
输出结果:
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: "hello async"}
从结果中可以看到async函数返回的是一个promise
对象,如果在函数中 return
一个直接量,async
会把这个直接量通过 Promise.resolve()
封装成 Promise
对象。
如果asyn
函数没有返回值
async function testAsync1() {
console.log("hello async");
}
let result1 = testAsync1();
console.log(result1);
结果
hello async
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}
结果返回Promise.resolve(undefined)
。
从字面意思上看await
就是等待,await
等待的是一个表达式,这个表达式的返回值可以是一个promise
对象也可以是其他值。
很多人以为await
会一直等待之后的表达式执行完之后才会继续执行后面的代码,实际上await
是一个让出线程的标志。await
后面的函数会先执行一遍,然后就会跳出整个async
函数来执行后面js
栈(后面会详述)的代码。等本轮事件循环执行完了之后又会跳回到async
函数中等待await
后面表达式的返回值,如果返回值为非promise
则继续执行async
函数后面的代码,否则将返回的promise
放入promise
队列(Promise
的Job Queue
)
async/await
执行顺序先看一个例子
function testSometing() {
console.log("执行testSometing");
return "testSometing";
}
async function testAsync() {
console.log("执行testAsync");
return Promise.resolve("hello async");
}
async function test() {
console.log("test start...");
const v1 = await testSometing();//关键点1
console.log(v1);
const v2 = await testAsync();
console.log(v2);
console.log(v1, 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...
执行testSometing
promise start..
test end...
testSometing
执行testAsync
promise
hello async
testSometing hello async
当test
函数执行到
const v1 = await testSometing();
的时候,会先执行testSometing
这个函数打印出“执行testSometing”的字符串,然后因为await
会让出线程就会区执行后面的
var promise = new Promise((resolve)=> { console.log("promise start.."); resolve("promise");});//关键点2
然后打印出“promise start..”接下来会把返回的这promise
放入promise
队列(Promise
的Job Queue
),继续执行打印“test end…”,等本轮事件循环执行结束后,又会跳回到async
函数中(test函数),等待之前await
后面表达式的返回值,因为testSometing
不是async
函数,所以返回的是一个字符串“testSometing”,test
函数继续执行,执行到
const v2 = await testAsync();
和之前一样又会跳出test函数,执行后续代码,此时事件循环就到了promise
的队列,执行promise.then((val)=> console.log(val));
then后面的语句,之后和前面一样又跳回到test函数继续执行。
这个就是在async/await
函数之后js的执行顺序,我们再看一个列子把testSometing函数前面加上async
async function testSometing() {
console.log("执行testSometing");
return "testSometing";
}
async function testAsync() {
console.log("执行testAsync");
return Promise.resolve("hello async");
}
async function test() {
console.log("test start...");
const v1 = await testSometing();
console.log(v1);
const v2 = await testAsync();
console.log(v2);
console.log(v1, v2);
}
test();
var promise = new Promise((resolve)=> { console.log("promise start.."); resolve("promise");});//3
promise.then((val)=> console.log(val));
console.log("test end...")
输出结果:
test start...
执行testSometing
promise start..
test end...
promise
testSometing
执行testAsync
hello async
testSometing hello async
和上一个例子比较发现promise.then((val)=> console.log(val));
先与console.log(v1);
执行了,原因是因为现在testSometing
函数加了async
,返回的是一个Promise
对象要要等它resolve
,所以将当前Promise
推入队列,所以会继续跳出test函数执行后续代码。之后就开始执行promise
的任务队列了,所以先执行了promise.then((val)=> console.log(val));
因为这个Promise
对象先推入队列;