javascript为单线程脚本语言,HTML5推出web worker标准,允许创建多个子线程,不过子线程完全受主线程控制,并且不可以操作DOM。
浏览器 EventLoop 机制
- 所有同步任务都在主线程上执行,形成执行栈
- 主线程之外还有一个任务队列,只要异步任务有了运行结果,就在任务队列中放置一个事件
- 执行栈中所有同步任务执行完成,系统就会读取任务队列,看看有哪些任务。那些对应的异步任务结束等待状态进入执行栈,开始执行
- 主线程不断重复以上三个步骤
node EventLoop 机制
- V8引擎解析JavaScript脚本
- 解析后的代码调用node API
- libuv库负责node API执行,他将不同的任务分配给不同的线程,形成一个EventLoop,以异步的方式把执行结果返回给V8引擎
- V8引擎将结果返回给用户
延伸-异步任务
异步任务可以分为宏任务与微任务,在任务队列中,先执行微任务,微任务执行完再执行宏任务,每次宏任务执行完,系统会先看有没有可执行的微任务。
宏任务列表
- I/O
- setTimeout
- setInterval
- requestAnimationFrame(浏览器)
- setImmediate(node)
微任务列表
- promise then/catch/finally
- async/await
- MutationObserver(浏览器)
- process.nextTick(node)
* process.nextTick 为当前执行栈尾部,下一次EventLoop读取任务队列之前触发回调函数
* setImmediate 为当前任务队列的尾部,每次EventLoop读取任务队列时触发回调函数
示例
console.log('start task')
setTimeout(() => {
console.log('setTimeout1')
process.nextTick(() => {
console.log('nextTick in setTimeout')
})
}, 0)
setImmediate(() => {
console.log('setImmediate 1')
setTimeout(() => {
console.log('setTimeout in setImmediate 1')
}, 0)
setImmediate(() => {
console.log('setImmediate 2')
})
setTimeout(() => {
console.log('setTimeout in setImmediate 2')
}, 0)
})
process.nextTick(() => {
console.log('nextTick 1')
process.nextTick(() => {
console.log('nextTick 2')
})
})
new Promise(()=> {
console.log('promise')
const chain = Promise.resolve()
chain.then(() => {
console.log('chain 1')
})
chain.then(() => {
console.log('chain 2')
})
})
console.log('end task')
// 执行结果:
// start task
// promise
// end task
// nextTick 1
// nextTick 2
// chain 1
// chain 2
// setTimeout1
// nextTick in setTimeout
// setImmediate 1
// setImmediate 2
// setTimeout in setImmediate 1
// setTimeout in setImmediate 2
/**
* 提示!
* setImmediate 与 setTimeout 执行顺序随机,只有setImmediate嵌套时固定先执行setImmediate
*/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。