ES6-Promise 原理分析

promise是什么

以下来自百度
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

promise图解

promise有两大状态,未决状态和已决状态

  1. 未决状态:PENDING
  2. 已决状态:RESOLVED/REJECTED

promise中有两个方法可以将未决状态推向已决状态

  1. resolve:将状态从PENDING推向RESOLVED
  2. reject:将状态从PENDING推向REJECTED

promise还有两个列表用来存储成功后的回调函数与失败的回调函数
thenables/catchables

图解如下
在这里插入图片描述

手动封装MyPromise

既然明白了Promise的原理,那么promise内部就要有4个变量来存储相应的状态

在这里封装的MyPromise没有添加链式调用的功能,因为链式调用还没有搞懂。。。如果你明白链式调用的原理,请联系15011177648(微信同号)

  1. 当前状态
  2. 值(后续处理函数的参数)
  3. 成功状态回调列表
  4. 失败状态回调列表
class MyPromise {
    // 接受一个函数
    constructor(fun) {
        // 定义后续处理参数
        this.value = undefined;
        // 定义promise状态,最初是未决
        this.status = "PENDDING";
        // 定义成功后续处理函数列表
        this.thenableList = [];
        // 定义失败后续处理函数列表
        this.catchableList = [];
        // 将状态推向成功的函数
        let resolve = (value) => {
            this.changeStatus('RESOLVED', value);
            // 循环执行成功队列的函数
            this.thenableList.forEach((item) => {
                item(this.value)
            })
        }
        // 将状态推向失败的函数
        let reject = (value) => {
            this.changeStatus('REJECTED', value);
            // 循环执行失败队列的函数
            this.catchableList.forEach((item) => {
                item(this.value)
            })
        }
        // 尝试执行传进来的函数
        try {
            fun(resolve, reject);
        } catch (e) {
            reject(e)
        }
    }
    // 改变状态
    changeStatus(newStatus, value) {
        // 由于状态是不可逆的,所以先盘算是不是未决,不是直接返回
        if (this.status != "PENDDING") return
        this.status = newStatus;
        this.value = value
    }
    // 后续处理
    settleHandle(newStatus, able, list) {
        // 判断参数是否为函数
        if (typeof able != 'function') {
            return
        }
        // 判断状态
        if (this.status == newStatus) {
            // 在Promise中,后续处理函数应该是放在事件微队列,但是jsAPI无法将事件放入微队列,这里使用setTimeout的宏队列代替
            // 如果已经是已决了,直接执行
            setTimeout(() => {
                able(this.value)
            }, 0)
        } else {
            // 不是已决的话就放进任务队列,等待状态改变
            list.push(able);
        }
    }
    // 添加成功处理函数
    then(thenable, catchable) {
        this.settleHandle('RESOLVED', thenable, this.thenableList);
        // 由于成功处理函数可接受两个参数,所以这里也要调一下失败处理函数
        this.catch(catchable)
    }
    // 添加失败处理函数
    catch(catchable) {
        this.settleHandle('REJECTED', catchable, this.catchableList)
    }
}

私有化变量

在上面的promise中,完成了promise的基本功能,但是真正的Promise的某些变量,外接是访问不到的(除了then,catch,finally都访问不到),所以我们使用闭包加符号来私有化变量。

有关符号的使用,我会再写一篇博客来介绍

const MyPromise = (() => {
    const PENDING = 'pending',
        RESOLVED = 'resolved',
        REJECTED = 'rejected',
        promiseValue = Symbol('后续处理参数'),
        promiseStatus = Symbol('当前状态'),
        thenables = Symbol('成功后的调用函数列表'),
        catchables = Symbol('成功后的调用函数列表'),
        changeStatus = Symbol('改变状态'),
        settleHandle = Symbol('后续处理');
    return class MyPromise {
        // 新状态, then的参数
        [changeStatus](newStatus, result, queue) {
            if (this[promiseStatus] !== PENDING) {
                //状态无法变更
                return;
            }
            this[promiseStatus] = newStatus;
            this[promiseValue] = result;
            queue.forEach(handle => {
                handle(this[promiseValue])
            });
        }
        constructor(executor) {
            this[promiseValue] = undefined;
            this[promiseStatus] = PENDING;

            this[thenables] = [];
            this[catchables] = [];

            const resolve = (result) => {
                this[changeStatus](RESOLVED, result, this[thenables]);
            }

            const reject = (err) => {
                this[changeStatus](REJECTED, err, this[catchables]);
            }

            try {
                executor(resolve, reject)
            } catch (err) {
                reject(err)
            }
        }
        // 后续事件, 立即执行状态, 后续事件列表
        [settleHandle](handle, status, queueList) {
            if (typeof handle !== 'function') {
                return
            }
            if (this[promiseStatus] == status) {
                setTimeout(() => {
                    handle(this[promiseValue])
                }, 0)
            } else {
                queueList.push(handle);
            }
        }
        then(thenable, catchable) {

            this[settleHandle](thenable, RESOLVED, this[thenables])
            this.catch(catchable)
        }
        catch(catchable) {
            this[settleHandle](catchable, REJECTED, this[catchables])
        }
    }
})()

Promise的静态方法

promise还有一些静态方法(这些静态方法怎么用就不做赘述了)

  1. all
  2. rece
  3. resolve
  4. reject

现在我们来实现一下这四个静态方法

const MyPromise = (() => {
    const PENDING = 'pending',
        RESOLVED = 'resolved',
        REJECTED = 'rejected',
        promiseValue = Symbol('后续处理参数'),
        promiseStatus = Symbol('当前状态'),
        thenables = Symbol('成功后的调用函数列表'),
        catchables = Symbol('成功后的调用函数列表'),
        changeStatus = Symbol('改变状态'),
        settleHandle = Symbol('后续处理');
    return class MyPromise {
        // ...(略)
        // 静态方法-resolve
        static resolve(data) {
            if (data instanceof MyPromise) {
                return data
            } else {
                return MyPromise(resolve => {
                    resolve(data)
                })
            }
        }
        // 静态方法-reject
        static reject(reason) {
            return MyPromise((resolve, reject) => {
                reject(reason)
            })
        }
        // 静态方法-all
        static all(ProList) {
            return new MyPromise((resolve, reject) => {
                // 给每个promise对象注册后续处理
                // 成功就查看是否全部成功,全部成功让all的promise也成功
                // 失败就直接失败
                let result = ProList.map((p) => {
                    let obj = {
                        value: undefined,
                        isResolved: false
                    }
                    p.then((data) => {
                        obj.value = data;
                        obj.isResolved = true;
                        // then的后续处理函数是放在微队列,所以当后续处理函数执行时result已经有值了
                        let filterProList = result.filter((item) => !item.isResolved);
                        if (filterProList.length == 0) {
                            resolve(result.map(r => r.value))
                        }
                    }, (reason) => {
                        reject(reason)
                    })
                    return obj
                })
            })
        }
        // 静态方法-race
        static race(ProList) {
            // 给每个promise注册后续处理函数,变为已决就将rece的promise推向对应状态
            return new MyPromise((resolve, reject) => {
                ProList.forEach((p) => {
                    p.then(data => { 
                        resolve(data) 
                    },err => { 
                        reject(err) 
                    })
                })
            })
        }
    }
})()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章