JS_微任务与宏任务
JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。
为了协调事件、用户交互、脚本、UI 渲染和网络处理等行为,防止主线程的不阻塞,Event Loop 的方案应用而生。
同步任务 | 自上而下,逐条执行 | |
---|---|---|
微任务 | 执行到微任务时,将微任务插入在当前任务列的最下面 | promise.then、async、await |
宏任务 | 执行到宏任务时,将宏任务插入到下个任务列的最顶端 | setTimeout、setInterval 、AJAX |
微任务执行机制较为简单,而宏任务需要回收。
- 在执行同步任务时,如果遇到微任务,将微任务塞到当前任务流的最后。
- 执行到宏任务时,将宏任务插入到下一个新任务列的最顶端 。
console.log("1");
new Promise(function (resolve) {
console.log("2");
resolve();
}).then(function () {
console.log("3");
})
setTimeout(function () {
console.log("4")
}, 0);
console.log("5");
//1 2 5 3 4
//125同步,3微任务,4宏任务
- 微任务中的宏任务与宏任务中的微任务
Promise.resolve().then(function () {
console.log("ddd")
setTimeout(function () {
console.log("aaa");
}, 0)
})
setTimeout(function () {
console.log("bbb");
Promise.resolve().then(function () {
console.log("ccc");
})
}, 0)
//ddd bbb ccc aaa
//见下面的注释
- 在执行第一个微任务promise之前,第二个任务列开头便加载了宏任务,setTimeout
- 毫无疑问,尽管宏任务先加载了,但还是先执行微任务,打印 ddd
- 打印了ddd,接着微任务中的宏任务,在第三个任务列开头加载了宏任务
- 来到了第二个任务列,打印在第一个任务列中加载的bbb
- 在第二个任务列中,将当前宏任务中的微任务ccc 装载到最后并执行
- 最后执行第三个任务列开头的aaa
- 加大难度
setTimeout(function () {
new Promise(function (resolve, reject) {
console.log('异步宏任务promise');
resolve();
}).then(function () {
console.log('异步微任务then')
})
console.log('异步宏任务');
}, 0)
new Promise(function (resolve, reject) {
console.log('同步宏任务promise');
resolve();
}).then(function () {
console.log('同步微任务then')
})
console.log('同步宏任务')
运行结果:
同步宏任务promise
同步宏任务
同步微任务then
异步宏任务promise
异步宏任务
异步微任务then
- 来一道终极变态简单的面试题吧
console.log(1);//1
document.addEventListener("14", function () {
console.log(14);//7
})
new Promise(function (resolve) {
resolve();
console.log(2);//2
setTimeout(function () {
console.log(3);//8
}, 0);
Promise.resolve().then(function () {
console.log(4);//4
setTimeout(function () {
console.log(5);//11
}, 0);
setTimeout(function () {
(async function () {
console.log(6)//12
return function () {
console.log(7);//14
}
})().then(function (fn) {
console.log(8)//13
fn();
})
}, 0);
})
new Promise(function (resolve) {
console.log(9);//3
resolve();
}).then(function () {
new Promise(function (resolve, reject) {
console.log(10)//5
reject();
}).then(function () {
setTimeout(function () {
console.log(11)
}, 0)
console.log(12);
}).catch(function () {
console.log(13);//6
var evt = new Event("14");
document.dispatchEvent(evt);
})
})
});
setTimeout(function () {
console.log(15);//9
Promise.resolve().then(function () {
console.log(16);//10
})
}, 0)
// 1 2 9 4 10 13 14 3 15 16 5 6 8 7