专栏首页前端小菜鸟自己实现一个JavaScript Promise类
原创

自己实现一个JavaScript Promise类

Promise对象用于表示一个异步操作的最终状态以及操作的值。Promise本质上是一个绑定了回调的对象,区别于将回调传入函数内部。

Promise 属性和方法

我们通过构造函数去创建promise实例:

let promise = new Promise( function(resolve, reject) {...} /* executor */ );

Promise构造函数传入一个参数executor函数,executor是带有resolve和reject两个参数的函数。在构造函数返回Promise实例对象前executor被调用,当前状态被初始化成pedding状态,executor内部执行一些异步操作,当异步操作执行完毕根据执行情况:当成功执行则调用resolve函数将promise状态更新为fulfilled,否则执行reject函数设置promise状态为rejected。

一个Promise只有三种状态:

  1. pedding:初始状态
  2. fulfilled:操作成功完成
  3. rejected:操作失败

Promise API

a. Promise方法

方法

描述

Promise.reject(reason)

返回一个Promise对象,状态设置为失败并传递失败原因给处理函数

Promise.resolve(value)

返回一个promise对象,能够将value以Promise是形式使用

Promise.all(iterable)

iterable 是一个数组对象,只有当iterable每个promise对象都成功执行才会触发,返回一个数组对象保存promise对象数组的执行结果,和iterable每个对象的顺序保持一致

Promise.race(iterable)

返回一个Promise,按照iterable数组任意promise对象最先执行完毕的结果立即返回,成功执行返回执行结果还是失败返回原因

b. 构造函数

构造函数

描述

new Promise( function(resolve, reject)){}

通过new关键字创建实例对象,resoleve是异步函数成功执行调用,否则执行reject

c. 原型链方法

方法

描述

promise.then(onFulfilled, onRejected)

当promise解析完成,则调用onFulfilled,如果promise拒绝,则执行onRejected,两个都是可选的参数

promise.catch

promise拒绝,等价于 promise.then(undefined, onRejected)

动手实现一个Promise类

我们已经整理了Promise对象的属性和方法,已经promise对象从原型链继承的属性和方法,现在我们需要一步一步自己去实现一个Promise类。

const STATE = {
    PENDING: 'pending',
    FULFILLED: 'fulfilled',
    REJECTED: 'rejected'
}
const emptyObj = {};

function handleFun(fun, resolve, reject) {
    try {
        fun(resolve, reject);
    } catch (err) {
        reject(err);
    }
}
function getFun(fun) {
    return typeof fun === 'function' ? fun : function(e) {return e};
}

function PromiseFun(fu) {
    if(fu === emptyObj) return;
    this.defaultState = STATE.PENDING;
    this.state = STATE.PENDING;
    this.data = 0;
    this.onFulfilledList = [];
    this.onRejectedList = [];

    const resolve = (val) => {
        if(this.state !== STATE.PENDING) return;
        this.state = STATE.PENDING;
        this.data = val;
        this.onFulfilledList.forEach(fun => {
            fun(val);
        })
    }
    const reject = (reason) => {
        if(this.state !== STATE.PENDING) return;
        this.state = STATE.REJECTED;
        this.onRejectedList.forEach(fun => {
            fun(reason);
        })
    }
    handleFun(resolve, reject);
} 

PromiseFun.prototype.then = function(onFulfilled, onRejected) {
    let self = this;
    onFulfilled = getFun(onFulfilled);
    onRejected = getFun(onRejected);
    switch(this.state) {
        case STATE.PENDING:
            let fun_pending = function(resolve, rejected) {
                self.onFulfilledList.push(function(val) {
                    try {
                        let data = onFulfilled(self.data);
                        if(data instanceof PromiseFun) {
                            data.then(resolve, reject);
                        } else {
                            resolve(data);
                        }
                    } catch (err) {
                        reject(err);
                    }
                })
                self.onRejectedList.push(function(val) {
                    try {
                        let data = onRejected(self.data);
                        if(data instanceof PromiseFun) {
                            data.then(resolve, reject);
                        } else {
                            reject(data)
                        }
                    } catch (err) {
                        reject(err);
                    }
                })
            }
            return new PromiseFun(fun_pending);
        case STATE.FULFILLED:
            let fun_fulfilled = function(resolve, reject) {
                try {
                    let data = onFulfilled(self.data);
                    if(data instanceof PromiseFun) {
                        data.then(resolve, reject);
                    }else {
                        resolve(data);
                    }
                } catch (err) {
                    reject(err);
                }
            }
            return new PromiseFun(fun_fulfilled);
        case  STATE.REJECTED:
            let fun_rejected = function(resolve, reject) {
                try {
                    let data = onRejected(self.data);
                    if(data instanceof PromiseFun) {
                        data.then(resolve, reject);
                    }else {
                        reject(data);
                    }
                } catch(err) {
                    reject(err);
                }
            }  
            return new PromiseFun(fun_rejected); 
    }
}

PromiseFun.prototype.catch = function(onRejected) {
    return this.then(null, onRejected);
}

PromiseFun.resolve = function(value) {
    return new PromiseFun(function(resolve, rejected) {
        resolve(value);
    }) 
}

PromiseFun.reject = function(reason) {
    return new PromiseFun(function(resolve, rejected) {
        rejected(reason);
    })
}

PromiseFun.all = function(promiseArr) {
    if(!Array.isArray(promiseArr)) return;
    let len = promiseArr.length;
    let count = 0;
    let resultArr = [];
    for(let i = 0; i < len; i++) {
        let item = promiseArr[i];
        PromiseFun.resolve(item).then(function(val) {
            count++;
            resultArr[i] = val;
            if(count === len) {
                return reason(resultArr);
            }
        }, function(reason) {
            reject(reason)
        })
    }

}

参考

  1. 使用Promise | MDN
  2. Promise | MDN
  3. JavaScript Promise简介
  4. Promises/A+规范
  5. 剖析Promise内部结构,一步一步实现一个完整的、能通过所有Test case的Promise类
  6. promise Core.js
  7. Promise简易实现

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 理解JavaScript立即执行函数

    立即执行函数通常包含两种使用格式,具体使用那一种风格可以根据个人习惯和团队规范选择:

    伯爵
  • Vue响应式原理

    Vue是数据驱动视图实现双向绑定的一种前端框架,采用的是非入侵性的响应式系统,不需要采用新的语法(扩展语法或者新的数据结构)实现对象(model)和视图(vie...

    伯爵
  • ES6装饰器Decorator的实现原理

    NOTE Decorators are an experimental feature that may change in future releases...

    伯爵
  • Promise的几个方法

    我们都会觉得虽然是链式调用,对比回调会清晰一点,但是并没有想象中的那么美好。所以Promise提供了几个方法。

    wade
  • ES6 Promise

    Promise 的状态只有两种可能,从 pending 变为 fulfilled 和 从 pending 变为 rejected,一旦状态变化,就不会再改变

    Leophen
  • JavaScript之Promise对象

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,...

    laixiangran
  • JS魔法堂:剖析源码理解Promises/A规范

    一、前言                                 Promises/A是由CommonJS组织制定的异步模式编程规范,有不少库已根据该规...

    ^_^肥仔John
  • Promise 与 RxJS

    首先是需要源源不断的流出数据的场景,因为Promise是一次性的,不适合做这类工作。 比如说把事件/定时器抽象成Rx的Observable更合适,事件可以响应很...

    剑行者
  • 手写源码系列(二)——Promise相关方法

    本文首发于知乎专栏——前端面试题汇总,大家可以通过文章底部的阅读原来来访问原文地址

    用户1687375
  • 手写一个Promise/A+,完美通过官方872个测试用例

    前段时间我用两篇文章深入讲解了异步的概念和Event Loop的底层原理,然后还讲了一种自己实现异步的发布订阅模式:

    蒋鹏飞

扫码关注云+社区

领取腾讯云代金券