JavaScript 的异步事件背景:
事件处理
// 当元素被点击时,会触发对应事件处理函数
<div onclick="handleClick">
<script>
function handleClick() {
console.info('handle click.')
}
</script>
回调事件
// 当读取文件完成后,会调用相应回调事件
fs.readFile('path', (err, content) => {
if (err) {
throw err
}
console.info('content: ', content)
})
优缺点
- 事件处理函数
- 只适用于响应用户交互和完成类似的低频功能,对于更复杂的需求来说不是很灵活
- 回调函数
- 嵌套地狱:
fs.readFile('path', (err, content) => { if (err) { throw err } fs.writeFile('filename', (err, result) => { if (err) { throw err } fs.openFile('path', (err, result) => { if (err) { throw err } console.info('open file success!') }) }) })
Promise
定义:
Promise 是异步操作结果的占位符,承诺在未来某个时刻 完成
- 3 种状态
- pending // 进行中
- fulfilled // 成功
- rejected // 失败
一旦异步操作结束,Promise 即变为 settle 状态
- 创建未完成的 Promise:
let promise = new Promise(function (resolve, reject) {
resolve()
reject()
})
promise
.then(() => console.info('resolved'))
.catch(() => console.info('rejected'))
每次调用
then
或catch
都会创建一个新任务,当 Promise 被解决时执行
console.info('script start')
const promise = new Promise(resolve => {
console.info('Promise executed')
resolve()
})
promise.then(() => console.info('resolved'))
console.info('script end')
// script start
// Promise executed
// script end
// resolved
-
具体执行机制是啥样呢
- 当
new Promise(executor)
时,Promise 构造器中的执行器 executor 会立即执行; - 在执行器中,无论调用
resolve()
还是reject()
,都会触发一个异步操作; - 传入
then()
或catch()
的函数会被添加到任务队列中异步执行
- 当
-
创建已完成的 Promise
Promise.resolve()
Promise.resolve(42).then(result => console.info(result)) // 42
Promise.reject()
Promise.reject('error').catch(err => console.error(err)) // 'error'
-
非 Promise 的
Thenable
对象
Promise.resolve()
和Promise.reject()
方法都可接受非 Promise 的 Thenable 对象作为参数,
这些方法会创建一个新的 Promise 并在then()
函数中被调用。
const thenable = {
then: (resolve, reject) => resolve(42)
}
const promise = Promise.resolve(thenable)
promise.then(result => console.info(result)) // 42
- Promise 返回的也是 Promise 对象,因此可链式调用
const promise = new Promise(resolve => setTimeout(resolve, 1000))
promise
.then(() => console.info('first promise'))
.then(() => console.info('second promise'))
.then(() => { throw Error('error') })
.catch(err => console.error(err))
-
任务队列、事件循环、宏任务、微任务
-
错误捕获机制
- 如果执行器内部抛出了错,则 Promise 的错误处理程序会被调用:
const promise = new Promise(() => { throw Error('error') }) promise.catch(err => console.error(err.message)) // 'error' // 每个执行器中都隐含一个 try-catch 块,上例等价于: let promise = new Promise((resolve, reject) => { try { throw Error('error') } catch (err) { reject(err) } }) promise.catch(err => console.error(err.message)) // 'error'
- 全局的 Promise 拒绝处理:
- Node.js 环境的拒绝处理:
unhandledRejection
rejectionHandled
- 浏览器环境的拒绝处理
unhandlerejection
rejectionhandled
- Node.js 环境的拒绝处理:
-
响应多个 Promise:
Promise.all()
const promise1 = new Promise(resolve => setTimeout(() => resolve(42), 1000)) const promise2 = new Promise(resolve => setTimeout(() => resolve(43), 2000)) Promise.all([promise1, promise2]).then(results => console.info(results)) // 2s 后输出 [42, 43]
Promise.race()
const promise1 = new Promise(resolve => setTimeout(() => resolve(42), 1000)) const promise2 = new Promise(resolve => setTimeout(() => resolve(43), 2000)) Promise.race([promise1, promise2]).then(result => console.info(result)) // 1s 后输出 42
-
生成器 + Promise