We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
var date = new Date() console.log(1, new Date() - date) setTimeout(() => { console.log(2, new Date() - date) }, 500) Promise.resolve().then(console.log(3, new Date() - date)) while(new Date() - date < 1000) {} console.log(4, new Date() - date)
求上面的输出顺序和输出值,为什么?
答案:
1 0 3 1 4 1000 2 1000
其中,关于时间差结果可能因为计算机性能造成的微小差异,可忽略不计
你答对了吗?下面我们由浅入深探索本题
首先,看一下 event loop 的基础必备内容
event loop
event loop 执行顺序:
script
Web Worker
微任务包括:MutationObserver、Promise.then()或catch()、Promise为基础开发的其它技术,比如fetch API、V8的垃圾回收过程、Node独有的process.nextTick 、 Object.observe(已废弃;Proxy 对象替代)
MutationObserver
Promise.then()或catch()
Promise为基础开发的其它技术,比如fetch API
V8
Node独有的process.nextTick
Object.observe
Proxy
宏任务包括:script 、setTimeout、setInterval 、setImmediate 、I/O 、UI rendering 、 postMessage 、 MessageChannel
setTimeout
setInterval
setImmediate
I/O
UI rendering
postMessage
MessageChannel
注意: 下面的题目都是执行在浏览器环境下
遇到不好理解的,可结合 promise 源码 进行理解,就很简单了
promise
var promise = new Promise((resolve, reject) => { console.log(1) resolve() console.log(2) }) promise.then(()=>{ console.log(3) }) console.log(4) // 1 // 2 // 4 // 3
解析:
Promise
then
new Promise
1
resolve()
resolved
resolve
2
promise.then
4
3
var promise = new Promise((resolve, reject) => { console.log(1) }) promise.then(()=>{ console.log(2) }) console.log(3) // 1 // 3
var promise = new Promise((resolve, reject) => { console.log(1) }) promise.then(console.log(2)) console.log(3) // 1 // 2 // 3
.then
.catch
value => value
then()
console.log(2)
Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .then(console.log) // 1
then(2)
then(Promise.resolve(3))
var promise = new Promise((resolve, reject) => { console.log(1) resolve() reject() }) promise.then(()=>{ console.log(2) }).catch(()=>{ console.log(3) }) console.log(4) // 1 // 4 // 2
reject()
promise.catch
rejected
catch
Promise.resolve(1) .then(res => { console.log(res); return 2; }) .catch(err => { return 3; }) .then(res => { console.log(res); }); // 1 // 2
resolve(1)
console.log(res)
return 2
resolve(2)
setTimeout(() => { console.log(1) }) Promise.resolve().then(() => { console.log(2) }) console.log(3) // 3 // 2 // 1
setTimout
Promise.resolve().then
var promise = new Promise((resolve, reject) => { console.log(1) setTimeout(() => { console.log(2) resolve() }, 1000) }) promise.then(() => { console.log(3) }) promise.then(() => { console.log(4) }) console.log(5) // 1 // 5 // 2 // 3 // 4
pending
callback
5
现在看,本题就很简单了
1 0
500ms
3 1
whlie
1000ms
4 1000
2 1000
Promise 构造函数是同步执行的, then 方法是异步执行的
.then 或者 .catch 的参数期望是函数,传入非函数则会直接执行
Promise的状态一经改变就不能再改变,构造函数中的 resolve 或 reject 只有第一次执行有效,多次调用没有任何作用
reject
.then方法是能接收两个参数的,第一个是处理成功的函数,第二个是处理失败的函数,再某些时候你可以认为catch是.then第二个参数的简便写法
当遇到 promise.then 时, 如果当前的 Promise 还处于 pending 状态,我们并不能确定调用 resolved 还是 rejected ,只有等待 promise 的状态确定后,再做处理,所以我们需要把我们的两种情况的处理逻辑做成 callback 放入 promise 的回调数组内,当 promise 状态翻转为 resolved 时,才将之前的 promise.then 推入微任务队列
The text was updated successfully, but these errors were encountered:
No branches or pull requests
求上面的输出顺序和输出值,为什么?
答案:
其中,关于时间差结果可能因为计算机性能造成的微小差异,可忽略不计
你答对了吗?下面我们由浅入深探索本题
由浅入深探索 Promise 异步执行
首先,看一下
event loop
的基础必备内容event loop
执行顺序:script
宏任务Web Worker
任务,有则执行微任务包括:
MutationObserver
、Promise.then()或catch()
、Promise为基础开发的其它技术,比如fetch API
、V8
的垃圾回收过程、Node独有的process.nextTick
、Object.observe
(已废弃;Proxy
对象替代)宏任务包括:
script
、setTimeout
、setInterval
、setImmediate
、I/O
、UI rendering
、postMessage
、MessageChannel
注意: 下面的题目都是执行在浏览器环境下
遇到不好理解的,可结合
promise
源码 进行理解,就很简单了1. 同步 + Promise
题目一:
解析:
Promise
构造函数是同步执行的,then
方法是异步执行的new Promise
,执行构造函数同步代码,输出1
resolve()
, 将promise
的状态改为了resolved
,并且将resolve
值保存下来,此处没有传值2
promise
,往下执行,碰到promise.then
这个微任务,将其加入微任务队列4
promise.then
微任务,输出3
题目二:
解析:
new Promise
,执行构造函数同步代码,输出1
promise.then
,因为promise
中并没有resolve
,所以then
方法不会执行3
题目三:
解析:
.then
或者.catch
的参数期望是函数,传入非函数则会发生值透传(value => value
)new Promise
,执行构造函数同步代码,输出1
then()
的参数是一个console.log(2)
(注意:并不是一个函数),是立即执行的,输出2
3
题目四:
解析:
then(2)
、then(Promise.resolve(3))
发生了值穿透,直接执行最后一个then
,输出1
题目五:
解析:
new Promise
,执行构造函数同步代码,输出1
resolve()
, 将promise
的状态改为了resolved
,并且将resolve
值保存下来,此处没有传值reject()
,此时promise
的状态已经改为了resolved
,不能再重新翻转(状态转变只能是pending —> resolved 或者 pending —> rejected,状态转变不可逆)promise
,往下执行,碰到promise.then
这个微任务,将其加入微任务队列promise.catch
这个微任务,此时promise
的状态为resolved
(非rejected
),忽略catch
方法4
promise.then
微任务,输出2
题目六:
解析:
resolve(1)
, 状态改为了resolved
,并且将resolve
值保存下来console.log(res)
输出1
return 2
实际上是包装成了resolve(2)
resolved
,catch
方法被忽略then
,输出2
2. 同步 + Promise + setTimeout
题目一:
解析:
setTimout
被放入宏任务队列Promise.resolve().then
,then
方法被放入微任务队列3
then
微任务,输出2
setTimeout
宏任务,执行输出1
题目二:
解析:
promise.then
时,如果当前的Promise
还处于pending
状态,我们并不能确定调用resolved
还是rejected
,只有等待promise
的状态确定后,再做处理,所以我们需要把我们的两种情况的处理逻辑做成callback
放入promise
的回调数组内,当promise
状态翻转为resolved
时,才将之前的promise.then
推入微任务队列Promise
构造函数同步执行,输出1
,执行setTimeout
setTimeout
加入到宏任务队列中promise.then
放入promise
的回调数组内promise.then
放入promise
的回调数组内5
setTimeout
宏任务,输入2
,执行resolve
,promise
状态翻转为resolved
,将之前的promise.then
推入微任务队列setTimeout
宏任务出队,检查微任务队列3
4
回到开头
现在看,本题就很简单了
解析:
1 0
setTimeout
,定时500ms
后执行,此时,将setTimeout
交给异步线程,主线程继续执行下一步,异步线程执行setTimeout
Promise.resolve().then
,.then
的参数不是函数,直接执行(value => value
) ,输出3 1
whlie
,等待1000ms
,在此期间,setTimeout
定时500ms
完成,异步线程将setTimeout
回调事件放入宏任务队列中4 1000
setTimeout
宏任务,输入2 1000
总结
Promise
构造函数是同步执行的,then
方法是异步执行的.then
或者.catch
的参数期望是函数,传入非函数则会直接执行Promise
的状态一经改变就不能再改变,构造函数中的resolve
或reject
只有第一次执行有效,多次调用没有任何作用.then
方法是能接收两个参数的,第一个是处理成功的函数,第二个是处理失败的函数,再某些时候你可以认为catch
是.then
第二个参数的简便写法当遇到
promise.then
时, 如果当前的Promise
还处于pending
状态,我们并不能确定调用resolved
还是rejected
,只有等待promise
的状态确定后,再做处理,所以我们需要把我们的两种情况的处理逻辑做成callback
放入promise
的回调数组内,当promise
状态翻转为resolved
时,才将之前的promise.then
推入微任务队列The text was updated successfully, but these errors were encountered: