咱们都知道JavaScript是单线程的,也就是说同一时间只能干一件事。这是由于JavaScript主要是用来操做DOM
的,若是变成多线程,浏览器就懵逼了,不知道该听谁的了。可是虽然js是单线程,可是彻底能够模拟多线程,靠的就是Event Loop
。node
咱们都知道js中的代码分 同步
和 异步
,所谓的 异步
其实就是不会阻塞咱们的主线程,等待主线程的代码执行完毕才会执行。callback setTimeout setInterval Promise ...
这些都是都是咱们耳熟能详的 异步
代码ajax
如图所示,js中的内存分为 堆内存(heap)
和 栈内存(stack)
, 堆内存
中存的是咱们声明的object
类型的数据,栈内存
中存的是 基本数据类型
以及 函数执行时
的运行空间。咱们的 同步
代码就放在 执行栈
中,那异步代码呢?浏览器会将 dom事件 ajax setTimeout
等异步代码放到队列中,等待执行栈
中的代码都执行完毕,才会执行队列中的代码,是否是有点像发布订阅模式。promise
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
console.log(3);
复制代码
根据以前说的,setTimeout 会被放到队列中,等待执行栈中的代码执行完毕才会执行,因此会输出1, 3, 2
浏览器
可是异步
代码也是有区别的:bash
console.log(1)
setTimeout(() => {
console.log(2)
}, 0)
Promise.resolve().then(() => {
console.log(3)
})
复制代码
输出的永远是1, 3, 2
, 也就是说 promise
在 setTimeout
以前执行了。这是由于 异步任务
分为 微任务(microtask)
和 宏任务(task)
,执行的顺序是 执行栈中的代码 => 微任务 => 宏任务
。多线程
执行栈
中的代码永远最早执行promise MutationObserver...
执行栈
中的代码执行完毕,会在执行宏任务队列
以前先看看微任务队列
中有没有任务,若是有会先将微任务队列
中的任务清空才会去执行宏任务队列
setTimeout setInterval setImmediate(IE专用) messageChannel...
执行栈
和微任务队列
都执行完毕才会执行,而且在执行完每个宏任务
以后,会去看看微任务队列
有没有新添加的任务,若是有,会先将微任务
队列中的任务清空,才会继续执行下一个宏任务
setTimeout(() => {
console.log('timeout1')
Promise.resolve().then(() => {
console.log('promise1')
})
Promise.resolve().then(() => {
console.log('promise2')
})
}, 100)
setTimeout(() => {
console.log('timeout2')
Promise.resolve().then(() => {
console.log('promise3')
})
}, 200)
复制代码
setTimeout
塞到宏任务队列中setTimeout1
时间到了执行的时候,首先打印timeout1,而后在微任务队列中塞入promise1
和promise2
setTimeout1
执行完毕后,会去微任务队列检查是否是空的,他发现了有两个promise
,会把两个promise
按顺序执行完再去执行下一个宏任务promise
执行完毕后会微任务队列中没有任务了,会去宏任务中执行下一个任务 setTimeout2
setTimeout2
执行的时候,先打印一个timeout2,而后又在微任务队列中塞了一个promise2
setTimeout2
执行完毕后会去微任务队列检查,发现有一个promise3,会将promise3
执行timeout1 promise1 promise2 timeout2 promise3
咱们都知道Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,也就是可以让js在服务端运行。可是Node中的Event Loop是用libuv模拟的,它将不一样的任务分配给不一样的线程,造成一个Event Loop,以异步的方式将任务的执行结果返回给V8引擎。dom
process.nextTric promise setImmediate...
setTimeout setInterval...
Node中的Event Loop会在每次切换队列的时候 清空微任务队列,也就会会将当前队列都执行完,在进入下一阶段的时候检查一下微任务中有没有任务异步
setTimeout(() => {
console.log('timeout1')
Promise.resolve().then(() => {
console.log('promise1')
})
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
setTimeout(() => {
console.log('timeout2')
Promise.resolve().then(() => {
console.log('promise3')
})
}, 0)
复制代码
setTimeout
塞到宏任务队列中setTimeout1
时间到了执行的时候,首先打印timeout1,而后在微任务队列中塞入promise1
和promise2
setTimeout1
执行完毕后,继续执行下一个setTimeout2
setTimeout2
执行的时候,先打印一个timeout2,而后又在微任务队列中塞了一个promise2
timeout1 timeout2 promise1 promise2 promise3