js 是一种单线程语言 简单来说 只有一条通道 在任务多的情况下 就会出现拥挤的情况 这种情况就产生了 ‘多线程’ 但是这种 ‘多线程’ 是通过单线程模仿的 也就是假的 那么就产生了 同步、异步任务。
1 js是单线程的 但分同步异步
2 宏任务、微任务皆为 异步任务 它们都属于一个队列
宏任务 script、setTimeout、setInterval、postMessage、MessageChannel、setImmediate
微任务 Promise.then、Object.observe、MutationObserver、process.nextTick
先执行同步代码
遇到 异步宏任务 则将 异步宏任务 放入 宏任务队列中
遇到 异步微任务 则将 异步微任务 放入 微任务队列中
当所有同步代码执行完毕后
再将 异步微任务 从队列中调入 主线程执行
微任务执行完毕后
再将 异步宏任务 从队列中调入 主线程执行
一直循环 直至 所有任务执行完毕
setTimeout(function(){
console.log(1)
})
new Promise(function(resolve){
console.log(2)
resolve()
}).then(function(){
console.log(3)
}).then(function(){
console.log(4)
})
console.log(5)
// 2 5 3 4 1
- 遇到 setTimeout 异步宏任务 放入宏任务队列中
- 遇到 new Promise new Promise 在实例化时所执行的代码是同步 所以输出2
- Promise then 异步微任务 放入微任务队列中
- 遇到同步任务 输出5 主线程中同步任务执行完
- 将 异步微任务 从队列中调入 主线程执行 输出3 4 微任务队列为空
- 将 异步宏任务 从队列中调入 主线程执行 输出1 宏任务队列为空
setTimeout(() => {
new Promise(resolve => {
resolve()
}).then(() => {
console.log('test')
})
console.log(4)
})
new Promise(resolve => {
resolve()
console.log(1)
}).then( () => {
console.log(3)
Promise.resolve().then(() => {
console.log('before timeout')
}).then(() => {
Promise.resolve().then(() => {
console.log('also before timeout')
})
})
})
console.log(2)
// 1, 2, 3, before timeout, also before timeout, 4, test
- 遇到 setTimeout 异步宏任务 放入宏任务队列中
- 遇到 new Promse new Promse 在实例化的时候 所执行的代码是同步 所以输出1
- 而 Promise.then 异步微任务 放入微任务队列中
- 遇到同步任务 输出2 主线程中同步任务执行完
- 将 异步微任务 从队列中调入 主线程执行 输出3
此微任务中 又有微任务 Promise.resolve().then(微任务A).then(微任务B) 将其依次放入微任务队列中- 从微任务队列中 取出 微任务A 放入 主线程中 输出 before timeout
- 从微任务队列中 取出 微任务B 放入 主线程中 微任务B 又有 微任务C 放入微任务队列中
- 从微任务队列中 取出 微任务C 放入 主线程中 输出 also before timeout 微任务队列为空
- 从宏任务队列中 取出 宏任务 放入 主线程中 此任务 有一个微任务D 放入微任务队列中 接下来输出4 宏任务队列为空
- 从微任务队列中 取出 微任务D 放入 主线程中 输出 test 微任务队列为空
console.log(1)
setTimeout(function() {
console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {
resolve(4)
})
p.then(data => {
console.log(data)
})
console.log(3)
// 1, 3, 4, 2
- 遇到同步任务 输出 1
- 遇到 setTimeout 异步宏任务 放入宏任务队列中
- 遇到 Promise new Promise 在实例化的时候所执行的代码是同步 但由于 new Promse 没有输出事件 所以接着执行 遇到 .then
- 执行 .then 异步微任务 放入 微任务队列中
- 遇到同步任务 输出3 主线程中同步任务执行完
- 从 微任务队列中 取出 微任务 放入 主线程中 输出 4 主线程中微任务执行完
- 从 宏任务队列中 取出 宏任务 放入 主线程中 输出 2 主线程中宏任务执行完
console.log(1)
setTimeout(function() {
console.log(2)
new Promise(function(resolve) {
console.log(3)
resolve()
}).then(function() {
console.log(4)
})
})
new Promise(function(resolve) {
console.log(5)
resolve()
}).then(function() {
console.log(6)
})
setTimeout(function() {
console.log(7)
new Promise(function(resolve) {
console.log(8)
resolve()
}).then(function() {
console.log(9)
})
})
console.log(10)
// 1, 5, 10, 6, 2, 3, 4, 7, 8, 9
- 遇到同步任务 输出1
- 遇到 setTimeout 异步宏任务 放入宏任务队列中
- 遇到 Promise new Promise 在实例化的时候所执行的代码是同步 所以输出5 所以接着执行 遇到 .then
- 执行 .then 异步微任务 放入 微任务队列 中
- 遇到 setTimeout 异步宏任务 放入 宏任务队列中
- 遇到同步任务 输出10 主线程中同步任务执行完
- 从 微任务队列中 取出 微任务 放入 主线程中 输出 6 主线程中微任务执行完
- 从 宏任务队列中 取出 宏任务 放入 主线程中 执行第一个 输出 2 3 4
- 再执行第二个 setTimeout 输出 7 8 9 主线程中宏任务执行完
new Promise((resolve, reject) => {
resolve(1)
new Promise((resolve, reject) => {
resolve(2)
}).then(data => {
console.log(data)
})
}).then(data => {
console.log(data)
})
console.log(3)
// 3, 2, 1
- 遇到 Promise new Promise 在实例化的时候所执行的代码是同步 但由于 没有输出事件
所以接着往下执行 遇到 new Promse 没有输出事件 再接着往下执行 遇到 .then 异步微任务 放入微任务队列中- 再接着 .then 异步微任务 放入微任务队列中
- 遇到同步任务 输出 3 主线程中同步任务执行完
- 从微任务队列中 取出 微任务 放入 主线程 中 输出 2 3 主线程中微任务执行完 任务队列为空
先同步后异步
异步 包含 宏任务 微任务
异步 遇到 微任务 先执行微任务 执行完后 如果没有微任务 就执行下一个宏任务