前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自己实现一个JavaScript Promise类

自己实现一个JavaScript Promise类

原创
作者头像
伯爵
修改2019-10-30 10:50:53
6380
修改2019-10-30 10:50:53
举报
文章被收录于专栏:前端小菜鸟

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类。

代码语言:txt
复制
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简易实现

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Promise 属性和方法
    • Promise API
    • 动手实现一个Promise类
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档