Skip to content

前端异步编程

异步处理概念

异步处理是指在不等待某个操作的情况下,可以继续执行其他操作。异步处理可以提高程序的运行效率,减少等待时间,提高用户体验。

异步处理的实现方式

异步处理的实现方式有以下几种:

  • 回调函数
javascript
function fetchData(callback) {
    // 异步操作
    setTimeout(() => {
        const data = 'Hello World'
        callback(data)
    }, 1000)
}

fetchData((data) => {
    console.log(data)
})
  • Promise
javascript
function fetchData() {
    return new Promise((resolve, reject) => {
        // 异步操作
        setTimeout(() => {
            const data = 'Hello World'
            resolve(data)
        }, 1000)
    })
}

fetchData().then(data => {
    console.log(data)
})
  • async/await
javascript
async function fetchData() {
    // 异步操作
    const data = await new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('Hello World')
        }, 1000)
    })
    return data
}

fetchData().then(data => {
    console.log(data)
})

异步处理常见场景与处理策略

  • 网络请求
  • 定时任务
  • 事件绑定
  • 大量数据处理 Web Worker

处理策略

  • 回调函数
  • Promise
  • async/await
  • 发布/订阅模式
  • Generator 函数
  • promise.all
  • 预加载资源
  • 事件监听

手写简版 Promise

Promise规范

  1. 初始状态为 pending
  2. 执行了 resolve Promise状态为 fulfilled
  3. 执行了 reject Promise状态为 rejected
  4. Promise状态不可逆
  5. Promise中有throw error会被捕获,并转换为reject状态
  6. then接受两个回调,一个是成功的回调,一个是失败的回调,只有当Promise状态为fulfilled时才会执行成功的回调,只有当Promise状态为rejected时才会执行失败的回调
  7. 存在定时器,需要等定时器结束之后才会执行then的回调
  8. 链式调用,then返回的Promise可以继续调用then。下一次的then的回调函数接收上一次的回调函数的返回值。
  9. all
    1. 接收一个数组,数组中的元素都是Promise对象。
    2. 返回一个新的Promise对象,只有当所有Promise对象都执行完毕后才会执行成功的回调。
    3. 如果有一个失败,就返回失败的结果
  10. race
  11. any
  12. allSettled

实现MyPromise

javascript
class MyPromise {
    constructor(executor) {
        // 初始化值
        this.initValue()
        this.initBind(this.resolve, this.reject)

        // 执行executor函数
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }

    initValue() {
        this.PromiseState = 'pending' // 初始状态为pending
        this.PromiseResult = null // 初始结果为null

        // 初始化任务队列
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []
    }

    initBind() {
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
    }

    resolve(value) {
        if (this.PromiseState !== 'pending') return // 如果状态不是pending,则直接返回
        this.PromiseState = 'fulfilled' // 状态变为fulfilled
        this.PromiseResult = value // 结果变为value

        while (this.onFulfilledCallbacks.length) {
            this.onFulfilledCallbacks.shift()(this.PromiseResult)
        }
    }

    reject(value) {
        if (this.PromiseState !== 'pending') return // 如果状态不是pending,则直接返回
        this.PromiseState = 'rejected' // 状态变为rejected
        this.PromiseResult = value // 结果变为value

        while (this.onRejectedCallbacks.length) {
            this.onRejectedCallbacks.shift()(this.PromiseResult)
        }
    }

    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value
        onRejected = typeof onRejected === 'function' ? onRejected : (value) => value
        const thenPromise = new MyPromise((resolve, reject) => {
            const resolvePromise = cb => {
                setTimeout(() => {
                    try {
                        const result = cb(this.PromiseResult)
                        if (result === thenPromise && result) {
                            throw new Error('不能返回本身')
                        }
                        if (result instanceof MyPromise) {
                            result.then(resolve, reject)
                        } else {
                            resolve(result)
                        }
                    } catch (e) {
                        reject(e)
                        throw new Error(e)
                    }
                })
            }
            if (this.PromiseState === 'fulfilled') {
                resolvePromise(onFulfilled)
            } else if (this.PromiseState === 'rejected') {
                resolvePromise(onRejected)
            } else if (this.PromiseState === 'pending') {
                this.onFulfilledCallbacks.push(onFulfilled.bind(this))
                this.onRejectedCallbacks.push(onRejected.bind(this))
            }
        })
        return thenPromise
    }

    static all(promises) {
        const result = []
        let count = 0
        return new MyPromise((resolve, reject) => {
            const addData = (value, index) => {
                result[index] = value
                count++

                if (count === promises.length) {
                    resolve(result)
                }
            }
            promises.forEach((promise, index) => {
                if (promise instanceof MyPromise) {
                    promise.then(value => {
                        addData(value, index)
                    }, error => reject(error))
                } else {
                    addData(promise, index)
                }
            })
        })
    }

    static allSettled(promises) {
        return new MyPromise((resolve, reject) => {
            const result = []
            let count = 0
            const addData = (status, value, index) => {
                result[index] = {
                    status,
                    value
                }
                count++

                if (count === promises.length) {
                    resolve(result)
                }
            }
            promises.forEach((promise, index) => {
                if (promise instanceof MyPromise) {
                    promise.then(value => {
                        addData('fulfilled', value, index)
                    }, (error) => {
                        addData('rejected', error, index)
                    })
                } else {
                    addData('fulfilled', promise, index)
                }
            })
        })
    }
}