js代码运行在单个线程上,所以要避免阻塞线程。
事件循坏要不断的检查调用堆栈( LIFO队列,后进先出 )
每次迭代中的事件循坏都会检查堆栈中的东西是否为空。
const bar = ()=>{ console.log('bar') }
const baz = ()=>{ console.log('baz') }
const foo = ()=>{
console.log('foo')
bar()
baz()
}
foo() // foo bar baz
// 执行的顺序
foo() → console.log('foo') → bar() → console.log('bar') → baz() → console.log('baz')
如何将函数推迟知道堆栈被清空 --- 消息队列
比如setTimeout()中的回调函数,用户点击事件等都会放到消息队列中。
事件循环会赋予调用堆栈的优先级,一旦为空,就会处理消息队列中的东西
const bar = ()=>{ console.log('bar') }
const baz = ()=>{ console.log('baz') }
const foo = ()=>{
console.log('foo')
setTimeout(bar, 0)
baz()
}
foo(); // foo baz bar
先执行堆栈,后执行消息队列
foo() → console.log('foo') → setTimeout() → baz() → console.log('baz') → bar() → conosole.log('bar')
promise会排在所有堆栈的后面,消息队列的最前面
const bar = ()=>{ console.log('bar') }
const baz = ()=>{ console.log('baz') }
const foo = ()=>{
console.log('foo')
setTimeout(bar, 0)
new Promise( (res, rej)=>{
res('在baz之后,bar之前')
} ).then( res=>consle.log(res) )
baz()
}
foo(); // foo baz 在baz之后,bar之前 bar
process.nextTick():告诉JS,当前堆栈调用结束后,要尽快调用这个函数,而不是排到消息队列中
const bar = ()=>{ console.log('bar') }
const baz = ()=>{ console.log('baz') }
const foo = ()=>{
console.log('foo')
setTimeout(bar, 0)
new Promise( (res, rej)=>{
res('在baz之后,bar之前')
} ).then( res=>console.log(res) )
// process.nextTick(()=>{console.log('end')})
baz()
}
// process.nextTick(()=>{console.log('end')})
foo(); // foo baz end 在baz之后,bar之前 bar //结果一样
setImmediate( ()=>{ } ):这个执行顺序一般在setTimeout()后执行,当然也有其他因素,暂未发现
详见nodejs官网:了解 setImmediate()