四处收集的Promise练习题,希望可以更深刻的掌握Promise和JavaScript的执行顺序,来做个汇总,包括题目和自己的理解,如果有错误希望大佬指正。
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve()
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)
上面代码中1,2,4均是同步执行,根据先后顺序输出,
promise.then
中的代码就是异步执行,需要同步任务执行结束之后才输出。但是要注意这个3的输出也需要
resolve()
即把Promise的状态更改为成功才会输出。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
let p2 = p1.then(() => {
throw new Error('error!!!')
})
console.log('promise1', p1)
console.log('promise2', p2)
setTimeout(() => {
console.log('promise1', p1)
console.log('promise2', p2)
}, 2000)
这里出现了p2是由p1.then返回的一个全新promise,他的状态是由p1来决定,当一开始输出的时候p1和p2都处于等待状态,1s后p1改变为成功状态,并且p1.then((resolve,reject)),就执行resolve函数,将p2的状态改为拒绝。
let p = new Promise((resolve, reject) => {
resolve('success1')
reject('error')
resolve('success2')
})
p.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})
这里很好理解,Promise的内部代码是同步的,并且状态更改之后不能再次更改。
Promise.resolve(1)
.then((res) => {
console.log(res)
return 2
})
.catch((err) => {
return 3
})
.then((res) => {
console.log(res)
})
Promise.resolve()
是将当前的Promise的状态更改为成功,并且传递值,所以下一个then中可以接收到这个值,并且输出。
之后then中的return相当于返回了一个新的Promise,并且携带需要 传递的参数,实现链式调用
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('once')
resolve('success')
}, 1000)
})
let start = Date.now()
p.then((res) => {
console.log(res, Date.now() - start)
})
p.then((res) => {
console.log(res, Date.now() - start)
})
这个题目也好理解,当1秒之后,promise的状态更改,Promise.then()可以调用多次,同时所有的then都能获取到res的值,并且输出。
Promise.resolve()
.then(() => {
return new Error('error!!!')
})
.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})
then
中就算抛出一个error对象也不会影响Promise的状态,返回任意一个非 promise 的值都会被包裹成 promise 对象,即 return new Error('error!!!') 等价于
return Promise.resolve(new Error('error!!!'))
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log())
这里then内部期望传入函数,如果 不是函数,就发生值穿透,最后
console.log
是输出的1
const first = () => (new Promise((resolve, reject) => {
console.log(3);
let p = new Promise((resolve, reject) => {
console.log(7);
setTimeout(() => {
console.log(5);
resolve(6);
}, 0)
resolve(1);
});
resolve(2);
p.then((arg) => {
console.log(arg);
});
}));
first().then((arg) => {
console.log(arg);
});
console.log(4);
第一轮事件循环,先执行宏任务,主script,new Promise立即执行,输出 3,执行p这个new Promise操作,输出 7,发现setTimeout,将回调函数放入下一轮任务队列(Event Quene),p的then,暂且命名为then1,放入微任务队列,且first也有then,命名为then2,放入微任务队列。执行console.log(4),输出 4,宏任务执行结束。
再执行微任务,执行then1,输出 1,执行then2,输出 3.
第一轮事件循环结束,开始执行第二轮。第二轮事件循环先执行宏任务里面的,也就是setTimeout的回调,输出 5.resolve(6)不会生效,因为p的Promise状态一旦改变就不会再变化了。
process.nextTick(() => {
console.log('nextTick')
})
Promise.resolve()
.then(() => {
console.log('then')
})
setImmediate(() => {
console.log('setImmediate')
})
console.log('end')
process.nextTick 和 promise.then 都属于 microtask,而 setImmediate 属于 macrotask,在事件循环的 check 阶段执行。事件循环的每个阶段(macrotask)之间都会执行 microtask,事件循环的开始会先执行一次 microtask。