2020-02-26

# Promise实现

```js

const PENDING = Symbol('PENDING');

const FULFILLED = Symbol('FULFILLED');

const REJECTED = Symbol('REJECTED');

class MyPromise {

    constructor(fn) {

        this.fulfilledQueue = [];

        this.rejectedQueue = [];

        this._status = PENDING;

        this._value  = null;

        // 执行成功队列中的回调函数

        const handleFulfilledQueue = () => {

            while(this.fulfilledQueue.length) {

                let fulfiledFn = this.fulfilledQueue.shift();

                fulfiledFn(this._value);

            };

        };

        // 执行失败队列中的回调函数

        const handleRejectedQueue = () => {

            while(this.rejectedQueue.length) {

                let rejectedFn = this.rejectedQueue.shift();

                rejectedFn(this._value);

            };

        };

        // 完成状态转变,执行回调队列中的回调函数

        const _resolve = (val) => {

            const fn = () => {

                if(this._status !== PENDING) {

                    return;

                }

                if(val instanceof MyPromise) {

                    val.then((res) => {

                        this._status = FULFILLED;

                        this._value = res;

                        handleFulfilledQueue();

                    }, (err) => {

                        this._status = REJECTED;

                        this._value = err;

                        handleRejectedQueue();

                    });

                } else {

                    this._status = FULFILLED;

                    this._value = val;

                    handleFulfilledQueue();

                }

            }

            // 保证promise 回调函数一定是在同步任务之后执行;

            setTimeout(fn, 0);

        }

        // 完成状态Pending到REJECTED的转变,执行rejected队列中的回调函数

        const _reject = (val) => {

            const fn = () => {

                if(this._status !== PENDING) {

                    return;

                }

                this._status = REJECTED;

                this._value = val;

                handleRejectedQueue();

            }

            setTimeout(fn, 0);

        }

        try { // 处理外部传入函数执行异常

            fn(_resolve, _reject);

        } catch(e) {

            return _reject(e);

        }

    }

    then(successFn, failFn) {

        return new MyPromise((resolve, reject) => {

            // 执行成功时的回调函数

            const handleSucess = (fn) => {

                try {

                    if(typeof fn === 'function') {

                        const res = fn(this._value);

                        if(res instanceof MyPromise) {

                            res.then(resolve, reject);

                        } else {

                            resolve(res);

                        }

                    } else {

                        resolve(this._value)

                    }

                } catch(e){

                    reject(e);

                }

            }

            // 执行失败时的回调函数

            const handleFail = (fn) => {

                try {

                    if(typeof fn === 'function') {

                        const res = fn(this._value);

                        if(res instanceof MyPromise) {

                            res.then(resolve, reject);

                        } else {

                            resolve(res);

                        }

                    } else {

                        reject(this._value);

                    }

                } catch(e) {

                    reject(e);

                }

            }

            switch(this._status){

                case PENDING:      // 异步任务尚未完成,将回调函数推入相应队列

                    this.fulfilledQueue.push(() => {

                        handleSucess(successFn);

                    });

                    this.rejectedQueue.push(() => {

                        handleFail(failFn);

                    });

                    break;

                case FULFILLED:    // 异步任务成功完成,执行成功回调函数

                    handleSucess(successFn);

                    break;

                case REJECTED:      // 异步任务已失败,执行失败回调函数

                    handleFail(failFn);

                    break;

                default:

                    console.log('Promise error status:', this._status);

                    break;

            };

        });

    }

    catch(failFn) {

        return this.then(null, failFn);

    }

    finally(finalFn){

        return this.then(finalFn, finalFn);

    }

    static resolve(val) {

        if(val instanceof MyPromise) {

            return val;

        } else {

            return new MyPromise((resolve, reject) =>{

                resolve(val);

            });

        }

    }

    static reject(val) {

        return new MyPromise((resolve, reject) => {

            reject(val);

        });

    }

    static all(promiseArr) {

        return new Promise((resolve, reject) =>{

            const len = promiseArr.length;

            let count = 0;

            let result = [];

            for(let i = 0; i < len; i++) {

                promiseArr[i].then((val) => {

                    count++;

                    result.push[val];

                    if(count === len){

                        resolve(result);

                    }

                }, (err) => {

                    reject(err);

                });

            }

        });

    }

    static race(promiseArr) {

        return new Promise((resolve, reject) =>{

            const len = promiseArr.length;

            for(let i = 0; i < len; i++) {

                promiseArr[i].then((val) => {

                    resolve(val);

                }, (err) => {

                    reject(err);

                });

            }

        });

    }

}

```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些阅读 2,054评论 0 2
  • # Ajax标签(空格分隔): 笔记整理---[TOC]### 从输入网址开始:- 在学习ajax之前,你应该先了...
    V8阅读 279评论 1 0
  • 在ES6当中添加了很多新的API其中很值得一提的当然少不了Promise,因为Promise的出现,很轻松的就给开...
    嘿_那个谁阅读 3,680评论 2 3
  • 一、vue的生命周期是什么 vue每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据...
    奔跑吧兄弟_凯凯阅读 1,150评论 0 0
  • 1.该函数属于#include 标准库中, 且是快速排序; 2.qsort函数声明:void qsort(voi...
    WellLin阅读 694评论 0 0