异步任务不是直接放入任务队列,而是先放入对应的浏览器处理线程。当调用栈为空时,会通过事件循环去轮询任务队列,当1秒钟之后setTimeout的回调会放入到任务队列中,等事件循环轮询到之后将它放入调用栈中执行。
同步异步执行流程
setTimeout(() => {
console.log(l);
}, 20);
console.log(2);
setTimeout(() => {
console.log(3);
}, 1);
console.log(4);
console.time("AA");
for (let i = 0; i < 90000000; i++) {
// do soming
}
console.timeEnd("AA"); //=>AA: 33ms 左右
console.log(5);
setTimeout(() => {
console.log(6);
}, 2);
console.log(7);
setTimeout(() => {
console.log(8);
}, l0);
// 2 4 5 7 3 1 8 6
//字节面试题
async function async1() {
console.log("A");
await async2();
console.log("B");
}
async function async2() {
console.log("C");
}
console.log("D");
setTimeout(function () {
console.log("E");
}, 0);
async1();
new Promise(function (resolve) {
console.log("F");
resolve();
}).then(function () {
console.log("G");
});
console.log("H");
//D A C F H B G E
async await转换promise
await会等待这个promise的状态由pending转为fulfilled或者rejected。在此期间它会阻塞,延迟执行await语句后面的语句。
async function async1(){
console.log("A");
await async2();
console.log("B");
}
//async中如果没有await,就和普通函数一样
async function async2(){
console.log("C");
}
//转promise
function async1(){
console.log("A");
new Promise((resolve)=>{
console.log("C");
resolve();
}).then((res)=>{
console.log("B");
})
}
完整Event loop图解
阿里面试题
<button id="button">点击</button>
<script>
const button = document.querySelector("#button");
button.addEventListener('click',()=>{
Promise.resolve().then(()=> console.log("micro 1"));
console.log('listener 1')
});
button.addEventListener('click',()=>{
Promise.resolve().then(()=> console.log("micro 1"));
console.log('listener 1')
});
//1、浏览器窗口点击按钮
//2、执行下面语句
button.click();
</script>
- 在浏览器窗口点击按钮,触发这两个点击事件的函数,相当于两个宏任务,先执行第一个宏任务中的代码,promise.then()进入微任务,执行打印listener 1,在执行微任务打印micro 1,接着向下执行第二个宏任务。所以打印顺序为 listener 1/micro 1/listener 2/micro 4
- 执行button.click(),相当于执行一个函数,创建函数上下文进栈,这个函数中存在两个函数,执行第一个函数,promise进微任务队列,执行打印listener 1,继续向下执行第二个函数,promise进微任务队列,执行打印listener 2,至此click函数执行完毕出栈,主线程栈空,执行微任务打印micro 1、micro 2。所以打印顺序为listener 1/listener 2/micro 1/micro 2