ES6异步处理详解
同步与异步基础
常见的异步处理场景包括:定时器和Ajax请求。需要注意的是,异步任务的执行一定是在同步任务开始执行后才进行的。
Promise 详解
Promise是ES6中处理异步操作的重要特性。
基本语法
const p1 = new Promise((resolve, reject) => {
// Promise主体
})
resolve
:成功时调用的方法,返回成功结果reject
:失败时调用的方法,返回失败信息
使用then和catch处理结果
const p1 = new Promise((resolve, reject) => {
resolve('任务成功得到的数据')
// 或者
// reject('失败的信息')
})
p1.then(data => {
console.log(data)
})
.catch(err => {
console.log(err)
})
Promise链式调用
then方法可以返回新的promise对象,实现链式调用:
const p1 = new Promise((resolve, reject) => {
resolve('任务1成功得到的数据')
// reject('失败的信息')
})
p1.then(data => {
console.log(data)
return new Promise((resolve, reject) => {
resolve('任务2成功得到的数据')
// reject('失败的信息')
})
})
.catch(err => {
console.log(err)
})
通过.then
的链式调用,每一个后续的.then
都是在处理上一个.then
返回的promise,这样可以将原本嵌套的回调结构转换为线性代码,更加清晰易读。
为链式调用的then提供不同的错误处理
const p1 = new Promise((resolve, reject) => {
resolve('任务1成功得到的数据')
// reject('失败的信息')
})
p1.then(data => {
console.log(data)
return new Promise((resolve, reject) => {
resolve('任务2成功得到的数据')
// reject('失败的信息')
})
}, err => {
console.log('任务1失败了')
})
.then(data => {
console.log(data)
})
.catch(err => {
console.log(err)
})
注意:单个then的错误回调需要有返回信息,默认返回一个空的成功状态的promise。
如果希望后面的处理步骤都进入失败状态,可以:
- 返回一个新的失败状态的promise
- 抛出异常:
const p1 = new Promise((resolve, reject) => {
resolve('任务1成功得到的数据')
// reject('失败的信息')
})
p1.then(data => {
console.log(data)
return new Promise((resolve, reject) => {
resolve('任务2成功得到的数据')
// reject('失败的信息')
})
}, err => {
console.log('任务1失败了')
throw new Error('任务1失败')
})
.then(data => {
console.log(data)
})
.catch(err => {
console.log(err)
})
Async/Await
Async/Await是ES8引入的更优雅的异步处理方案,它建立在Promise之上,使异步代码看起来更像同步代码。
使用步骤
步骤1:准备一个返回promise对象的函数
function asyncTask() {
return new Promise((resolve, reject) => {
// 异步操作代码
const isSuccess = true
if (isSuccess) {
resolve('任务的返回结果')
} else {
reject('任务失败的处理结果')
}
})
}
步骤2:为使用await的函数添加async关键字
使用async
标记函数,这样就能在函数内部使用await
关键字。
async function main() {
console.log('任务1')
const data = await asyncTask()
console.log('任务2')
console.log('任务3')
console.log('任务4')
}
使用await等待Promise完成,可以让异步代码的写法更加直观和线性。
JavaScript事件循环机制
JavaScript事件循环是处理异步操作的核心机制,以下是其详细的运行步骤:
初始化:
- JavaScript引擎创建主线程执行栈和任务队列(包括宏任务队列和微任务队列)
- 页面加载时,整体的
script
脚本作为第一个宏任务放入宏任务队列
执行宏任务:
- 从宏任务队列中取出第一个宏任务,放入主线程执行栈执行
- 执行过程中遇到同步代码,按顺序执行
- 遇到异步操作(如
setTimeout
、Promise
),将回调函数放入相应的任务队列
检查微任务:
- 当前宏任务执行完后,检查微任务队列
- 如有微任务,依次执行所有微任务,直到微任务队列为空
执行渲染操作:
- 微任务队列清空后,浏览器可能会进行UI渲染操作
- UI渲染时机不固定,浏览器会根据自身策略决定何时渲染
循环往复:
- 完成上述步骤后,从宏任务队列取出下一个宏任务
- 重复步骤2到4,形成事件循环
异步操作的处理:
- 新的异步操作会产生新任务并放入相应队列
- 例如
fetch
完成后回调进入宏任务队列 Promise
状态改变后将then
或catch
回调放入微任务队列