前端学习——ES6异步处理

笔记 · 02-25 · 73 人浏览

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。

如果希望后面的处理步骤都进入失败状态,可以:

  1. 返回一个新的失败状态的promise
  2. 抛出异常:
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事件循环是处理异步操作的核心机制,以下是其详细的运行步骤:

  1. 初始化

    • JavaScript引擎创建主线程执行栈和任务队列(包括宏任务队列和微任务队列)
    • 页面加载时,整体的script脚本作为第一个宏任务放入宏任务队列
  2. 执行宏任务

    • 从宏任务队列中取出第一个宏任务,放入主线程执行栈执行
    • 执行过程中遇到同步代码,按顺序执行
    • 遇到异步操作(如setTimeoutPromise),将回调函数放入相应的任务队列
  3. 检查微任务

    • 当前宏任务执行完后,检查微任务队列
    • 如有微任务,依次执行所有微任务,直到微任务队列为空
  4. 执行渲染操作

    • 微任务队列清空后,浏览器可能会进行UI渲染操作
    • UI渲染时机不固定,浏览器会根据自身策略决定何时渲染
  5. 循环往复

    • 完成上述步骤后,从宏任务队列取出下一个宏任务
    • 重复步骤2到4,形成事件循环
  6. 异步操作的处理

    • 新的异步操作会产生新任务并放入相应队列
    • 例如fetch完成后回调进入宏任务队列
    • Promise状态改变后将thencatch回调放入微任务队列
前端
Theme Jasmine by Kent Liao