事件循环
学习与参考
- 并发模型与事件循环 - MDN
- 做一些动图,学习一下 EventLoop - 掘金
- 🌟45 道 Promise 面试题 - 掘金
- 一道常见又不失礼貌的异步笔试题,第一遍能做对吗 - 微信公众号文章
- 从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节 - 掘金
- 关于 JS 事件循环 event loop - 掘金
- 我们需要知道的 JS 异步编程 - 掘金
宏任务、微任务
JS 主线程不断的循环往复的从任务队列中读取任务,执行任务,这种运行机制称为事件循环(event loop)。
宏任务
- script (可以理解为外层同步代码)
- setTimeout、setInterval
- postMessage、MessageChannel(浏览器)
- UI rendering/UI交互事件(浏览器)
- setImmediate、I/O(Node.js)
微任务
- Promise.then/catch/finally
- MutaionObserver(浏览器)
- process.nextTick(Node.js)
运行机制
- 执行一个宏任务(栈中没有就从事件队列中获取)
- 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
- 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
- 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
- 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)
输出题
基础
js
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve('resolve1')
})
const promise2 = promise1.then(res => {
console.log(res)
})
console.log('1', promise1)
console.log('2', promise2)
/**
'promise1'
'1' Promise{<resolved>: 'resolve1'}
'2' Promise{<pending>}
'resolve1'
*/
then、catch、finally
javascript
setTimeout(() => console.log('a'), 0)
var p = new Promise(resolve => {
console.log('b')
resolve()
})
p.then(() => console.log('c'))
p.then(() => console.log('d'))
console.log('e')
// b e c d a
js
const promise = new Promise((resolve, reject) => {
reject('error')
resolve('success2')
})
promise
.then(res => {
console.log('then1: ', res)
})
.then(res => {
console.log('then2: ', res)
})
.catch(err => {
console.log('catch: ', err)
})
.then(res => {
console.log('then3: ', res)
})
/**
"catch: ", "error"
"then3: ", undefined
*/
js
const p1 = new Promise(resolve => {
setTimeout(() => {
resolve('resolve3')
console.log('timer1')
}, 0)
resolve('resovle1')
resolve('resolve2')
})
.then(res => {
console.log(res)
setTimeout(() => {
console.log(p1)
}, 1000)
})
.finally(res => {
console.log('finally', res)
})
/**
"resovle1"
"finally", undefined
"timer1"
Promise {<fulfilled>: undefined}
*/
js
Promise.resolve()
.then(() => {
return new Error('error!!!')
})
.then(res => {
console.log('then: ', res)
})
.catch(err => {
console.log('catch: ', err)
})
// then: Error: error!!!
js
Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)
// 1
javascript
new Promise((resolve, reject) => {
console.log('B')
resolve() // 1
})
.then(() => {
// 第一个 then
console.log('C')
new Promise((resolve, reject) => {
resolve() // 2
})
.then(() => {
console.log('D')
})
.then(() => {
// 3
console.log('E')
})
})
.then(() => {
// 第二个 then 加入
console.log('F')
})
//B C D F E
js
// - [说说下面代码的输出结果](https://fe.ecool.fun/topic/b42993a0-daf4-47df-b933-2fbded17cdff)
Promise.resolve()
.then(() => {
console.log(0)
return Promise.resolve(4)
})
.then(res => {
console.log(res)
})
/**
* 相当于
Promise.resolve().then(() => {
console.log(0);
return 4;
})
.then()
.then()
.then((res) => {
console.log(res)
})
*/
Promise.resolve()
.then(() => {
console.log(1)
})
.then(() => {
console.log(2)
})
.then(() => {
console.log(3)
})
.then(() => {
console.log(5)
})
.then(() => {
console.log(6)
})
// 0 1 2 3 4 5 6
js
Promise.resolve()
.then(
function success(res) {
throw new Error('error!!!')
},
function fail1(err) {
console.log('fail1', err)
},
)
.catch(function fail2(err) {
console.log('fail2', err)
})
// fail2 Error: error!!!
js
Promise.resolve('1')
.then(res => {
console.log(res)
})
.finally(() => {
console.log('finally')
})
Promise.resolve('2')
.finally(() => {
console.log('finally2')
return '我是finally2返回的值'
})
.then(res => {
console.log('finally2后面的then函数', res)
})
/**
"1"
"finally2"
"finally"
"finally2后面的then函数", "2"
*/
js
Promise.reject('err!!!')
.then(
res => {
console.log('success', res)
},
err => {
console.log('error', err)
},
)
.catch(err => {
console.log('catch', err) // !没走到这里
})
// error err!!!
setTimeout
javascript
setTimeout(() => {
console.log('timer1')
setTimeout(() => {
console.log('timer3')
}, 0)
}, 0)
setTimeout(() => {
console.log('timer2')
}, 0)
console.log('start')
/**
start
timer1
timer2
timer3
*/
setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise')
})
}, 0)
setTimeout(() => {
console.log('timer2')
}, 0)
console.log('start')
/**
start
timer1
promise
timer
*/
js
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
const promise2 = promise1.then(() => {
throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
console.log('promise1 2000', promise1)
console.log('promise2 2000', promise2)
}, 2000)
/**
promise1 Promise {<pending>}
promise2 Promise {<pending>}
Uncaught (in promise) Error: error!!!
promise1 2000 Promise {<fulfilled>: 'success'}
promise2 2000 Promise {<rejected>: Error: error!!!}
*/
all、race
js
function runAsync(x) {
const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))
return p
}
function runReject(x) {
const p = new Promise((res, rej) =>
setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x),
)
return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
.then(res => console.log('then', res))
.catch(err => console.log('err', err))
/**
1
3
2
"catch err", "Error: 2"
4
*/
async、await
js
async function async1() {
await async2()
console.log('async1')
return 'async1 success'
}
async function async2() {
return new Promise((resolve, reject) => {
console.log('async2')
reject('error')
})
}
async1().then(res => console.log(res))
/**
async2
Uncaught (in promise) error
*/
js
async function async1() {
try {
await Promise.reject('error!!!')
} catch (e) {
console.log(e)
}
console.log('async1')
return Promise.resolve('async1 success')
}
async1().then(res => console.log(res))
console.log('script start')
/**
"script start"
"error!!!"
"async1"
"async1 success"
*/
js
async function async1() {
console.log('async1 start')
await new Promise(resolve => {
console.log('promise1')
})
console.log('async1 success')
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
/**
"srcipt start"
"async1 start"
"promise1"
"srcipt end"
*/
/**
在async1中await后面的Promise是没有返回值的,也就是它的状态始终是pending状态,因此相当于一直在await,await,await却始终没有响应...
所以在await之后的内容是不会执行的,也包括async1后面的 .then。
*/
async function async1() {
console.log('async1 start')
await new Promise(resolve => {
console.log('promise1')
resolve('promise resolve')
})
console.log('async1 success')
return 'async1 end'
}
console.log('srcipt start')
async1().then(res => {
console.log(res)
})
new Promise(resolve => {
console.log('promise2')
setTimeout(() => {
console.log('timer')
})
})
/**
"srcipt start"
"async1 start"
"promise1"
"promise2"
"async1 success"
"async1 end"
"timer"
*/
javascript
const myPromise = Promise.resolve(Promise.resolve('Promise!'))
function funcOne() {
myPromise
.then(res => {
console.log('11', res)
return res
})
.then(res => console.log('12', res))
setTimeout(() => console.log('1 Timeout!'), 0)
console.log('1 Last line!')
}
async function funcTwo() {
const res = await myPromise
console.log('2', await res) //去掉await 结果又不一样
setTimeout(() => console.log('2 Timeout!'), 0)
console.log('2 Last line!')
}
funcOne()
funcTwo()
javascript
// 参考 [我们需要知道的 JS 异步编程](https://juejin.cn/post/6950785975693869069) 思考题与练习(字节)
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
return new Promise((resolve, reject) => {
resolve()
console.log('async2 promise')
})
}
async1()
new Promise(function (resolve) {
console.log('promise1')
resolve()
})
.then(function () {
console.log('promise2')
})
.then(function () {
console.log('promise3')
})
.then(function () {
console.log('promise4')
})
//async2 promise
//promise1
//promise2
//promise3
//async1 end
//promise4
// !!! 与上面的区别
async function async1() {
await async2()
console.log('async1 end')
}
function async2() {
return new Promise((resolve, reject) => {
resolve()
console.log('async2 promise')
})
}
async1()
new Promise(function (resolve) {
console.log('promise1')
resolve()
})
.then(function () {
console.log('promise2')
})
.then(function () {
console.log('promise3')
})
.then(function () {
console.log('promise4')
})
//async2 promise
//promise1
//async1 end
//promise2
//promise3
//promise4
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
return 'async return'
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1().then(function (message) {
console.log(message)
})
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('promise2')
})
console.log('script end')
//script start
//async1 start
//async2
//promise1
//script end
//async1 end
//promise2
//async return
//setTimeout
综合
js
const first = () =>
new Promise((resolve, reject) => {
console.log(3)
let p = new Promise((resolve, reject) => {
console.log(7)
setTimeout(() => {
console.log(5)
resolve(6)
console.log(p)
}, 0)
resolve(1)
})
resolve(2)
p.then(arg => {
console.log(arg)
})
})
first().then(arg => {
console.log(arg)
})
console.log(4)
/**
3
7
4
1
2
5
Promise {<fulfilled>: 1}
*/
javascript
var p = new Promise((res, rej) => {
res('hello one')
console.log('good morning')
})
function hello() {
console.log('hello begins')
return p
}
hello()
.then(res => {
console.log(res)
console.log('hello1111111111')
return 'hello two'
})
.then(res => {
console.log(res)
console.log('hello22222222222')
return 'hello three'
})
.then(res => {
console.log(res)
console.log('hello33333333333')
})
function test1() {
console.log('test1')
}
async function asy() {
console.log('asy begins')
await console.log('asy---111111')
console.log('async1')
await console.log('asy---222222')
console.log('asy ends')
}
asy()
test1()
function* gnrt() {
console.log(1)
yield console.log(11111111)
console.log(2)
yield console.log(22222222)
console.log(3)
yield console.log(33333333)
}
var result = gnrt()
result.next()
result.next()
result.next()
/*
good morning
hello begins
asy begins
asy---111111
test1
1
11111111
2
22222222
3
33333333
hello one
hello1111111111
async1
asy---222222
hello two
hello22222222222
asy ends
hello three
*/
javascript
console.log('start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
new Promise(() => {
let chain = Promise.resolve()
chain.then(() => console.log('chain1'))
chain.then(() => console.log('chain2'))
chain.then(() => console.log('chain3'))
})
let chain = Promise.resolve()
chain.then(() => console.log('chain4'))
console.log('end')
/*
start
end
chain1
chain2
chain3
chain4
setTimeout
*/
/*!!!注意区别*/
console.log('start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
new Promise(() => {
let chain = Promise.resolve()
chain
.then(() => console.log('chain1'))
.then(() => console.log('chain2'))
.then(() => console.log('chain3'))
})
let chain4 = Promise.resolve()
chain4.then(() => console.log('chain4'))
console.log('end')
/*
start
end
chain1
chain4
chain2
chain3
setTimeout
*/