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);

                });

            }

        });

    }

}

```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容

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