事件循环(event loop)
事件循环的过程
- 同步代码先进入执行栈(JavaScript是单线程,执行栈即主线程)执行,遇到异步代码,则放入宏任务队列或微任务队列
- 同步代码执行完,则微任务队列中的代码按先入先出的顺序从任务队列出来,进入执行栈,成为新的同步代码被执行
- 微任务队列为空,则将宏任务队列的任务放入执行栈执行,当宏任务队列为空时,回到执行栈执行同步代码,回到第1步。
异步任务分为宏任务和微任务,同步代码先于异步代码执行,微任务先于宏任务。
微任务包括:
1. MutationObserver、
2. Promise.then()或catch()、
3. Promise为基础开发的其它技术,比如fetch API、V8的垃圾回收过程、
4. Node独有的process.nextTick。
宏任务包括:
1. script(整体代码)
2. setTimeout
3. setInterval
4. I/O
5. UI交互事件
6. postMessage
7. MessageChannel
8. setImmediate(Node.js 环境)
基础题
题目1
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
})
console.log('1', promise1);
'promise1'
'1' Promise{<pending>}
分析:
- 执行同步代码
- 给promise1赋值
- 执行
console.log('promise1')
- 执行
console.log('1', promise1);
,此时promise1没有被resolve或者reject,因此状态还是pending
- 因为resolve和reject才是异步函数,但这里并没有调用并使用then赋值,所以异步任务队列均为空
题目2
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve('success')
console.log(2);
});
promise.then(() => {
console.log(3);
});
console.log(4);
输出:
···
1
2
4
3
···
分析:
- 执行执行栈中的同步代码
- 检查微任务队列,执行
resolve
,console.log(3)
被放入执行栈执行
题目3
const promise = new Promise((resolve, reject) => {
console.log(1);
console.log(2);
});
promise.then(() => {
console.log(3);
});
console.log(4);
输出:
1
2
4
分析:同题目2,但是因为promise
的resolve函数没有被调用,所以即使赋予了箭头函数也不会执行,于是就不会打印3。
promise.then只有在被改变了状态之后才会执行。
题目4
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve('resolve1')
})
const promise2 = promise1.then(res => {
console.log(res)
})
console.log('1', promise1);
console.log('2', promise2);
分析:
'promise1'
'1' Promise{<resolved>: 'resolve1'}
'2' Promise{<pending>}
'resolve1'
分析:
- 执行同步代码:
- 检查微任务队列,执行promise1的resolve,打印传入的"res",即打印“resolve1”
改一改代码:
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve('resolve1')
})
console.log('1', promise1);
const promise2 = promise1.then(res => {
console.log('ahead', promise2);
console.log("res",res);
})
//promise2.then(res=>console.log("promise2",res),rej=>console.log("err"));
console.log('1', promise1);
console.log('2', promise2);
setTimeout(console.log,0,'2',promise2);
输出:
promise1
1 Promise { <state>: "fulfilled", <value>: "resolve1" }
1 Promise { <state>: "fulfilled", <value>: "resolve1" }
2 Promise { <state>: "pending" }
ahead Promise { <state>: "pending" }
res resolve1
2 Promise { <state>: "fulfilled", <value>: undefined }
最终的promise2是处于fulfilled状态的
关于值传递的:
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve('resolve1')
})
const promise2 = promise1.then(res => {
console.log("res",res);
return "resolve2";
})
promise2.then(res=>console.log("promise2",res),rej=>console.log("err"));
console.log('1', promise1);
console.log('2', promise2);
setTimeout(console.log,0,'2',promise2);
输出:
promise1
1 Promise { <state>: "fulfilled", <value>: "resolve1" }
2 Promise { <state>: "pending" }
res resolve1
promise2 resolve2
2 Promise { <state>: "fulfilled", <value>: "resolve2" }
对比上面两段代码可以发现,当promise1的resolve没有显式返回一个值时,以const promise2 = promise1.then
创建的promise2获得的值是undefined。而当上一个期约返回一个值时,该值将被promise2传给相应的处理函数。
题目5
const fn = () => (new Promise((resolve, reject) => {
console.log(1);
resolve('success')
}))
fn().then(res => {
console.log(res)
})
console.log('start')
输出:
1
start
success
题目6
const fn = () =>
new Promise((resolve, reject) => {
console.log(1);
resolve("success");
});
console.log("start");
fn().then(res => {
console.log(res);
});
输出:
start
1
success
分析:同步代码前面的先执行。
感谢阅读。
百炼成钢!!!
参考:
【建议星星】要就来45道Promise面试题一次爽到底(1.1w字用心整理)
《JavaScript高级程序设计》(第四版)