1.
const promise = new Promise((resolve, reject) => { console.log(1); resolve(); console.log(2); }) promise.then(() => { console.log(3); }) console.log(4);
答案
遇到 Promise 之后立即执行,输出 1,2
执行同步代码,输出 4
执行 promise.then()
中的代码,输出 3
2.
console.log('script start'); setTimeout(function(){ console.log('setTimeout'); },0); new Promise(function(resolve){ console.log('promise1'); resolve(); console.log('promise2'); }).then(function(){ console.log('promise then'); }); console.log('script end');
答案
script start promise1 promise2 script end promise then setTimeout
首先 JavaScript 引擎会执行一个宏任务,注意这个宏任务一般是指主干代码本身,也就是目前的同步代码
执行过程中如果遇到微任务,就把它添加到微任务任务队列中
宏任务执行完成后,立即执行当前微任务队列中的微任务,直到微任务队列被清空
微任务执行完成后,开始执行下一个宏任务
如此循环往复,直到宏任务和微任务被清空
3.
const promise = new Promise((resolve, reject) => { resolve('success1'); reject('error'); resolve('success2'); }); promise.then((res) => { console.log('then:', res); }).catch((err) => { console.log('catch:', err); })
答案
then: success1
这里考察了 promise 的单向传递的特点,promise 有三种状态:
pending
resolved
rejected
这三种状态的转移只能是 pending -> resolved 或 pending -> rejected。不会出现 resolved -> rejected 或者 pending -> resolved -> rejected 等等,即状态只能从 pending 单向传递,且只能改变一次。
在 promise 中,resolve() 将 promise 的状态变为 resolved成功时调用,resolved 状态在先,先调用异步函数 promise.then(('success1') => { console.log('then:', 'success1'); })
promise 的状态一旦改变就不能修改了,因此 .catch() 和第二个 resolve('success2') 不会执行。
4.
Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .then(console.log)
答案
1
.then()
中的参数必须是函数,如果是非函数,则会发生值穿透,最终执行第三个 .then()
函数,参数为 1
。
5.
Promise.resolve(1) .then((res) => { console.log(res) return 2 }) .catch((err) => { return 3 }) .then((res) => { console.log(res) })
答案
1 2
promise.resolve() 返回一个新的 promise,执行第一个 .then(),参数为 1
打印 1,return 返回一个新的 promise,参数为 2
执行第二个 .then(),参数为 2,并打印出 2
6.
Promise.resolve() .then(() => { return new Error('error!!!') }) .then((res) => { console.log('then: ', res) }) .catch((err) => { console.log('catch: ', err) })
答案
then: Error: error!!!
这里的陷阱在于只有抛出错误时才会执行 .catch(),题目中并不是抛出错误,所以执行 .then()。
改成如下方式会执行 .catch():
return Promise.reject(new Error('error!!!'))
throw new Error('error!!!')
7.
const promise = Promise.resolve() .then(() => { return promise }) promise.catch(console.error)
答案
TypeError: Chaining cycle detected for promise #<Promise>
.then()
或 .catch()
返回的值不能是 promise 本身,否则会造成死循环。
8.
setTimeout(() => { console.log(1) Promise.resolve(3).then(data => console.log(data)) }, 0) setTimeout(() => { console.log(2) }, 0)
答案
1 3 2
先执行整体代码,没有发现微任务;
再执行下一个宏任务—setTimeout回调函数,打印出1;
遇到微任务—Promise 回调函数;
立即执行微任务,打印出3;
微任务队列被清空,执行下一个宏任务—下一个setTimeout回调函数,打印出2。
这道题有点不一样的是,Promise 回调这个微任务,是在 setTimeout 回调这个宏任务中,被触发的。不过无论怎样,它们都遵循 Event Loop 的模型规则。
9.
var pro = new Promise((res,rej)=>{ res(1); }); pro.then(res=>{ console.log(res); }); setTimeout(()=>{ console.log(2); }) pro.then(res=>{ console.log(res); })
答案
1 1 2
promise 对象赋值给了变量 pro,每个 .then()
都是独立的。
10.
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');
答案
script start async1 start async2 promise1 script end async1 end promise2 setTimeout
定义 async1(),async2(),不会立即执行
await async2(); 表示先执行 async2(),然后将 await 后面的代码当作 .then() 中的回调来处理
初始化 promise,promise 中的代码会立即执行
总结
基本上所有与异步相关的问题都可以用 event loop 来解释。最后,我们再来回顾一遍 event loop 的执行规则:
首先执行宏任务,这个宏任务一般指 主干代码,我们经常称之为同步代码;
执行过程中如果遇到了微任务,将其加入到微任务队列中;
执行完宏任务之后,开始执行微任务队列中的任务,直至微任务队列为空;
微任务执行完之后,开始执行下一个宏任务;
如何循环执行,直到宏任务和微任务都执行完。
作者:腐烂的橘子
链接:https://leetcode-cn.com/circle/discuss/sQXY3u/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。