简单实现一个promise

什么是Promise

  1. Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。

目的

1.首先定义构造函数Promise,外面要调用,返回Promise(先搭框架)
2.实现原型上的方法
3.实现构造函数上的方法

实现步骤

1..默认promise实例对象的值是初识状态是pending,通过new调用this指向实例对象,通过this.status给实例对象添加状态
2.还要定义一步结果的值,this.data=undefined作为异步返回值
3..promise中穿了一个函数executor,需要立即调用,executor(resolve, reject)传参为两个函数,定义resolve,和reject
4.. resolve做的事情:改变实力对象的状态为fulfilled,在严格模式下,想用this指向window,可以在外面缓存一下this
5.reject:改变实力对象的状态为rejected
6.及调用resolve有调用reject时,状态只能改一次,只能从pending变fulfilled或者rejected,promise中有可能电泳多次,只让第一次生效,判断一下是不是pending状态
7.调用时可能传参,一旦传参,实例对象返回该参数,

  1. 改成失败的状态还有throw error,希望抛出异常也会报错,给executor抱一个try..catch
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : // 检测是否是commonjs,如果是就以commonjs方式暴露
        typeof define === 'function' && define.amd ? define(factory) :  // 检测是否是AMD / requirejs,如果是就以AMD方式定义模块
            (global.Promise = factory()); // 既不是commonjs 也不是AMD,就是window.Promise = factory()
}(this, (function () {
    'use strict';
    'use strict';

    /*1.Promise对象传参穿的是一个函数executor,需要理解调用
    2.executor,有两个参数resolve().reject()都是函数
    3.每个Promise都有一个初始状态pending
    3.resolve接收参数为value,将实例对象的状态改为fulFilled
    4.reject接收参数为reason,并将reason返回

    * */
    function Promise(executor) {
        this.status = 'pending';
        this.data = undefined;
        this.callbacks = [];
        const _self = this;//为了保证后面this指向都是指向实例对象,将this缓存

        try {
            executor(resolve, reject)
        } catch (e) {
            reject(e)
        }

        function resolve(value) {//调用成功的回调函数
            if (_self.status === 'pending') {
                _self.status = 'fulFilled';//状态只能从pending改成fullFilled,并将参数传给实例对象
                _self.data = value;
                setTimeout(() => {
                    _self.callbacks.forEach((fnObj) => fnObj.onFulFilled())//需要异步执行
                })

            }
        }

        function reject(reason) {
            if (_self.status === 'fulFilled') {
                _self.status = 'rejected'
                _self.data = reason
                setTimeout(() => {
                    _self.callbacks.forEach((fnObj) => fnObj.onFulFilled())//需要异步执行
                })
            }
        }
    }

    Promise.prototype.then = function (onFulFilled, onRejected) {
      

    }
    Promise.resolve = function () {

    }
    Promise.reject = function () {

    }
    Promise.all = function () {

    }
    return Promise

})))

自己定义函数的是可以将原生的覆盖掉,先对then方法进行实现

  1. 每一个Promise对象都有三个状态
  • pending:初始状态
  • fulFilled :成功状态
  • rejected :失败的状态
  1. Promise对象的状态只能从pending变为fulFilled或者由pending变为rejected,不能有fulFilled变为rejected
  2. resolve传参数value,成功的数据,rejeced传参reason ,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
function Promise(executor) {
        this.status = 'pending';
        this.data = undefined;
        this.callbacks = [];//后面可以链式调用,有n个成功的回调或者失败的回调,定义成数组,为了方便依次执行
        const _self = this;//为了保证后面this指向都是指向实例对象,将this缓存

        try {
            executor(resolve, reject)
        } catch (e) {
            reject(e)
        }

        function resolve(value) {//调用成功的回调函数
            if (_self.status === 'pending') {
                _self.status = 'fulFilled';//状态只能从pending改成fullFilled,并将参数传给实例对象
                _self.data = value;
                setTimeout(()=>{//为了实现异步调用回调函数
                    _self.callbacks.forEach((fnObj)=>fnObj.onFulfilled())
                 })
            }
        }

        function reject(reason) {
            if (_self.status === 'fulFilled') {
                _self.status = 'rejected'
                _self.data = reason
                setTimeout(()=>{
                    _self.callbacks.forEach((fnObj)=>fnObj.onRejected())
                 })    
            }
        }
    }
Promise.prototype.then = function (onFullFilled, onRejected) {
      this.callbacks,push({
            onFulFilled:onFulFilled,
            onRejected:onrejected,
      })
    }

至此,完成了一个最简单的promise 的then方法实现,但是还不能链式调用
创建html文件引入自己创建的Promise,对这段代码进行测试

 const promise = new Promise((resolve, reject) => {
        resolve(11);
        // reject(22);
        // throw 22;
    });
    promise
    .then(
      (value) => {
        console.log('成功回调函数触发了111~', value);
     
      },
      (reason) => {
        console.log('失败回调函数触发了111~', reason);
      }
    )
    console.log('同步代码执行完了');
  1. 下面要开始实现链式调用了。
  • 要想实现then方法的链式调用返回值,then方法的返回值必须是一个新的promise对象
  • 添加解决(fulfillment)和拒绝(rejection)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve.
  • 当前操作的Promise对象,有三种状态,内种状态对应着不同的方法
  • pending 状态的 Promise 对象可能会变为fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法)
Promise.prototype.then = function (onFulFilled, onRejected) {
        // this.callacks.push({
        //     onFulFilled:onFulFilled,
        //     onRejected:onRejected
        // })
       //当前操作Promise实例对象没有改变状态,或者有一些异步函数在里面,也就是状态为pending时,需要将等待状态变化,一旦状态变化就去调用对应的函数
        let promise;
        const _self =this

        onFulFilled = typeof onFulFilled === 'function' ? onFulFilled : function (value) { return value };
        onRejected = typeof onRejected === 'function' ? onRejected : function (reason) { throw reason };

        if (this.status === 'pending'){
            promise = new Promise((resolve,reject)=>{
                _self.callacks.push({
                    onFulFilled:function () {
                        setTimeout(()=>{
                            try {
                                const result = onFulFilled(_self.data)//通过结果,来判断次Promise(1)的状态,返回结果有可能是普通值,也有可能是promise对象
                                if(result instanceof Promise){//假如返回值result的值为promise(2)对象,决定了promise(1)的状态是成功还是失败
                                    result.then(function (value) {
                                        resolve(value)
                                    },function (reason) {
                                        console.log(reason)
                                        reject(reason)
                                    })
                                    //简写
                                    // result.then(resolve,reject)
                                }else{
                                    resolve(result)
                                }
                            }catch (e) {
                                reject(e)//将promise1的状态改为reject,并将e传给了promise(0)
                            }

                        })
                    },
                    onRejected:function () {
                        setTimeout(()=>{
                            try {
                                const result = onRejected(_self.data)//通过结果,来判断次Promise(1)的状态,返回结果有可能是普通值,也有可能是promise对象
                                if(result instanceof Promise){//假如返回值result的值为promise(2)对象,决定了promise(1)的状态是成功还是失败
                                    result.then(function (value) {
                                        resolve(value)
                                    },function (reason) {
                                        console.log(reason)
                                        reject(reason)
                                    })
                                    //简写
                                    // result.then(resolve,reject)
                                }else{
                                    resolve(result)
                                }
                            }catch (e) {
                                reject(e)//将promise1的状态改为reject,并将e传给了promise(0)
                            }

                        })
                    }
                })
            })
        }else if(this.status === 'fulFilled'){//调用成功的回调函数,异步的
            promise = new Promise((resolve,reject)=>{//promise(1)
                setTimeout(()=>{
                    try {
                        const result = onFulFilled(_self.data)//通过结果,来判断次Promise(1)的状态,返回结果有可能是普通值,也有可能是promise对象
                        if(result instanceof Promise){//假如返回值result的值为promise(2)对象,决定了promise(1)的状态是成功还是失败
                             result.then(function (value) {
                               resolve(value)
                             },function (reason) {
                                 console.log(reason)
                                 reject(reason)
                             })
                            //简写
                           // result.then(resolve,reject)
                        }else{
                            resolve(result)
                        }
                    }catch (e) {
                        reject(e)//将promise1的状态改为reject,并将e传给了promise(0)
                    }

                })
            })
        }else{
            promise = new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    try {
                        const result = onRejected(_self.data)//通过结果,来判断次Promise(1)的状态,返回结果有可能是普通值,也有可能是promise对象
                        if(result instanceof Promise){//假如返回值result的值为promise(2)对象,决定了promise(1)的状态是成功还是失败
                            result.then(function (value) {
                                resolve(value)
                            },function (reason) {
                                console.log(reason)
                                reject(reason)
                            })
                            //简写
                            // result.then(resolve,reject)
                        }else{
                            resolve(result)
                        }
                    }catch (e) {
                        reject(e)//将promise1的状态改为reject,并将e传给了promise(0)
                    }

                })
            })
        }
       return promise//调用then方法需要返回一个promise对象,返回的这个promise对象
    };

公共代码可提取出来

  Promise.prototype.then = function (onFulFilled, onRejected) {
        // this.callacks.push({
        //     onFulFilled:onFulFilled,
        //     onRejected:onRejected
        // })
       //当前操作Promise实例对象没有改变状态,或者有一些异步函数在里面,也就是状态为pending时,需要将等待状态变化,一旦状态变化就去调用对应的函数
        let promise;
        const _self =this

        onFulFilled = typeof onFulFilled === 'function' ? onFulFilled : function (value) { return value };
        onRejected = typeof onRejected === 'function' ? onRejected : function (reason) { throw reason };

        if (this.status === 'pending'){
            promise = new Promise((resolve,reject)=>{
                _self.callacks.push({
                    onFulFilled:function () {
                        setTimeout(()=>{
                            handlePromiseStatus(resolve,reject,onFulFilled,_self.data)
                        })
                    },
                    onRejected:function () {
                        setTimeout(()=>{
                            handlePromiseStatus(resolve,reject,onRejected,_self.data)
                        })
                    }
                })
            })
        }else if(this.status === 'fulFilled'){//调用成功的回调函数,异步的
            promise = new Promise((resolve,reject)=>{//promise(1)
                setTimeout(()=>{
                    handlePromiseStatus(resolve,reject,onFulFilled,_self.data)
                })
            })
        }else{
            promise = new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    handlePromiseStatus(resolve,reject,onRejected,_self.data)
                })
            })
        }
       return promise//调用then方法需要返回一个promise对象,返回的这个promise对象
    };
    //上面try catch 只有函数不同,数据不同,因此提起公共代码
    function handlePromiseStatus(resolve,reject,onFn,_self_data){
        try {
            const result = onFn(_self_data)//通过结果,来判断次Promise(1)的状态,返回结果有可能是普通值,也有可能是promise对象
            if(result instanceof Promise){//假如返回值result的值为promise(2)对象,决定了promise(1)的状态是成功还是失败
                result.then(resolve,reject)
            }else{
                resolve(result)
            }
        }catch (e) {
            reject(e)//将promise1的状态改为reject,并将e传给了promise(0)
        }
    }
  1. catch 方法的实现
  • 本质上 catch方法就是then方法的失败
Promise.prototype.catch = function (onReject) {
        return this.then(null,onReject)
  };
  1. resolve 方法实现
  • resolve 方法的使用
    • 如上面提到的resolve本质上是个函数,在实际使用时有两种情况,如果value是一个promise函数,则应该将promise函数返回去,如果是普通参数,就应该返回一个promise值
Promise.resolve = function (value) {
    if (value instanceof Promise) return value;

    return new Promise((resolve, reject) => {
      resolve(value);
    })
  };
  1. reject 于resolve类似
Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    })
  };

  1. 实现all方法
  • 必须所有的promise 都成功才能返回成功,否则报错
Promise.all = function (promises) {
    let resolvedNum = 0;
    const promisesLength = promises.length;
    const results = new Array(promisesLength);

    return new Promise((resolve, reject) => {
      promises.forEach((promise, index) => {
        promise.then((value) => {
          // 成功
          // 保证对应的添加数据
          results[index] = value;
          resolvedNum++;
          if (resolvedNum === promisesLength) {
            // 全部成功
            resolve(results);
          }
        }, (reason) => {
          // 失败
          reject(reason);
        })
      })
    })
  };
  1. 实现race
  Promise.race = function (promises) {

    // return new Promise((resolve, reject) => promises.forEach((promise) => promise.then(resolve, reject)))
    return new Promise((resolve, reject) => {
      promises.forEach((promise) => {
        promise.then((value) => {
          // 成功
          resolve(value);
        }, (reason) => {
          // 失败
          reject(reason);
        })
      })

    })

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

推荐阅读更多精彩内容