但事件循环中的任务队列并不是唯一的,每个事件循环都有一个微任务队列以及多个宏任务队列。
异步任务可分为 宏任务 和 微任务两类,不同的API注册的异步任务会依次进入自身对应的队列中,然后等待 Event Loop 将它们依次压入执行栈中执行。从本质上来说,宏任务是ES6语法规定的,微任务是浏览器规定的,微任务的优先级要高于宏任务。
宏任务包含的API有:script(整体代码)、setTimeout、setInterval等
微任务包含的API有:Promise等
因此一次事件循环的大致过程为:
------------------------------------------
Async/Await可看作是Promise异步执行的优化,在其之前,Promise需要多个then()来链式调用,而有了await,就不必这么繁琐。
从定义上来看, async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
Promise中的异步体现在then和catch中,所以写在Promise中的代码是被当做同步任务立即执行的。而在async/await中,在出现await出现之前,其中的代码也是立即执行的。那么出现了await时候发生了什么呢?
其实,Async函数会返回一个Promise对象,Await用于等待函数的返回值,这个返回值可以是一个Promise对象,也可以是任意一个表达式的结果。
那么Promise中的代码会如何执行呢?
其实,Promise 构造函数中的第一个参数,是在 new 的时候执行,构造函数执行时,里面的参数进入执行栈执行;而后续的 .then 则会被分发到 microtask 的 Promise 队列中去。同理,在async/await中,函数从上到下依次执行,当碰到返回值时,await
会等待函数返回值并且将其放置在对应的任务队列后让出执行栈,JS向下执行其余代码,之后await得到返回值,执行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
console.log('script start');
setTimeout1(function() {
console.log('timeout1');
}, 10);
new Promise(resolve => {
console.log('promise1');
resolve();
setTimeout2(() => console.log('timeout2'), 10);
}).then(function() {
console.log('then1')
})
console.log('script end');
执行过程:
script start
promise1
script end
then1
timeout1
timeout2
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
代码执行过程:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
//async2做出如下更改:
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise3');
resolve();
}).then(function() {
console.log('promise4');
});
console.log('script end');
执行顺序:
script start
async1 start
promise1
promise3
script end
promise2
async1 end
promise4
setTimeout
async function async1() {
console.log('async1 start');
await async2();
//更改如下:
setTimeout(function() {
console.log('setTimeout1')
},0)
}
async function async2() {
//更改如下:
setTimeout(function() {
console.log('setTimeout2')
},0)
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout3');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
看了这么多,相信你已经能独立完成,因此不再赘述执行过程,只贴出结果看看你的想法对吗
注:await后的函数为setTimeout,因此会将其加入宏任务队列中
script start
async1 start
promise1
script end
promise2
setTimeout3
setTimeout2
setTimeout1
async function a1 () {
console.log('a1 start')
await a2()
console.log('a1 end')
}
async function a2 () {
console.log('a2')
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
Promise.resolve().then(() => {
console.log('promise1')
})
a1()
let promise2 = new Promise((resolve) => {
resolve('promise2.then')
console.log('promise2')
})
promise2.then((res) => {
console.log(res)
Promise.resolve().then(() => {
console.log('promise3')
})
})
console.log('script end')
结果
script start
a1 start
a2
promise2
script end
promise1
a1 end
promise2.then
promise3
setTimeout