事件循环
进程和线程
进程:计算机已经运行的程序
我们可以认为,启动一个应用程序,就会默认启动一个进程(也可能是多个进程)
线程:操作系统能够运行运算调度的最小单位
每一个进程中,都会启动一个线程来执行程序中的代码,这个线程被称为主线程---因此可以说进程是线程的容器
JavaScript的代码执行时在一个单独的线程中执行的:
意味着JavaScript代码,在同一个时刻只能做一件事,如果这件事非常耗时,意味着当前的线程就会被阻塞。
宏任务与微任务
事件循环中并非只维护一个队列,事实上是有两个队列
①宏任务队列:(macrotask queue) ajax、setTimeout、DOM监听、UI Rending等
②微任务队列(microtask queue):Promise的then回调、Mutation Observer API、queueMicrotask()等
事件循环对于两个队列的优先级
1.main script中的代码优先执行(编写的顶层script代码);
2.在执行任何一个宏任务之前(不是队列,是一个宏任务),都会先查看微任务队列中是否有任务需要执行
也就是宏任务执行之前,必须保证微任务队列是空的;
如果不为空,那么就优先微任务队列中的任务(回调)。
面试题①
setTimeout(function () {
console.log("set1");
new Promise(function (resolve) {
resolve();
}).then(function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log("then2");
});
});
new Promise(function (resolve) {
console.log("pr1");
resolve();
}).then(function () {
console.log("then1");
});
setTimeout(function () {
console.log("set2");
});
console.log(2);
queueMicrotask(() => {
console.log("queueMicrotask1")
});
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then3");
});
运行结果
async、await是Promise的一个语法糖
我们可以将await关键字后面执行的代码,看做是包裹着(resolve, reject) => {函数执行体}中的代码;
await的下一条语句,可以看做是then(res => {函数执行})中的代码;
面试题②
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')