-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
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
说说JS的事件循环机制 #39
Comments
JavaScript代码的执行过程中,除了依靠函数调用栈来搞定函数的执行顺序外,还依靠任务队列(task queue)来搞定另外一些代码的执行。整个执行过程,我们称为事件循环过程。一个线程中,事件循环是唯一的,但是任务队列可以拥有多个。任务队列又分为macro-task(宏任务)与micro-task(微任务),在最新标准中,它们被分别称为task与jobs。 macro-task大概包括:
micro-task大概包括:
整体执行,我画了一个流程图: 总的结论就是,执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。举个例子: 结合流程图理解,答案输出为:async2 end => Promise => async1 end => promise1 => promise2 => setTimeout async/await执行顺序我们知道 console.log('script start')
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
}
async1()
setTimeout(function() {
console.log('setTimeout')
}, 0)
new Promise(resolve => {
console.log('Promise')
resolve()
})
.then(function() {
console.log('promise1')
})
.then(function() {
console.log('promise2')
})
console.log('script end')
// script start => async2 end => Promise => script end => promise1 => promise2 => async1 end => setTimeout 分析这段代码:
let promise_ = new Promise((resolve,reject){ resolve(undefined)}) 执行完成,执行await后面的语句,输出
注意新版的chrome浏览器中不是如上打印的,因为chrome优化了,await变得更快了,输出为: // script start => async2 end => Promise => script end => async1 end => promise1 => promise2 => setTimeout 但是这种做法其实是违法了规范的,当然规范也是可以更改的,这是 V8 团队的一个 PR ,目前新版打印已经修改。 我们可以分2种情况来理解:
console.log('script start')
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
return Promise.resolve().then(()=>{
console.log('async2 end1')
})
}
async1()
setTimeout(function() {
console.log('setTimeout')
}, 0)
new Promise(resolve => {
console.log('Promise')
resolve()
})
.then(function() {
console.log('promise1')
})
.then(function() {
console.log('promise2')
})
console.log('script end') 输出为: // script start => async2 end => Promise => script end => => promise1 => promise2 => async1 end setTimeout 此时执行完awit并不先把await后面的代码注册到微任务队列中去,而是执行完await之后,直接跳出async1函数,执行其他代码。然后遇到promise的时候,把promise.then注册为微任务。其他代码执行完毕后,需要回到async1函数去执行剩下的代码,然后把await后面的代码注册到微任务队列当中,注意此时微任务队列中是有之前注册的微任务的。所以这种情况会先执行async1函数之外的微任务(promise1,promise2),然后才执行async1内注册的微任务(async1 end). |
对于后面两个案例我是这样的理解@LuckyWinty: 首先讨论讨论一下async函数的返回值,我们都知道是一个新的promise对象,而不是真正函数体里return的那个值,但是不同值的类型会影响返回promise对象的行为,分两种情况: 1.返回一个非promise类型的任何值,此时返回的promise对象会把返回值作为作为resolve的结果,根据案例结果,这个promise立即被加入到了微任务队列 Promise.resolve(value); 2.返回一个promise类型的值,此时返回的promise对象会继承返回值的状态和值,类似于promise的链式调用,当链条中上游的promise的回调没有执行(执行时会resolve下游的promise),下游的promise还是pending状态!上游执行后,下游promise任务会追加到微任务队列尾部 参照以下代码: Promise.resolve().then(() => {
console.log('promise 1');
}).then(() => {
console.log('promise 2');
});
Promise.resolve().then(() => {
console.log('promise 3');
});
// promise 1 => promise 3 => promise 2 个人观点: |
也可以吧,就是下游promise任务会追加到微任务队列尾部,感觉怪怪的,队列只有入队吧,没有直接加尾部一说吧 |
你理解的很对啊~ |
No description provided.
The text was updated successfully, but these errors were encountered: