/*
      自定义promise
        1. 执行MyPromise构造函数,要立即执行executor
        2. promise实例对象,内部有三种状态
          初始化 pending
          成功 resolved
          失败 rejected
          注意:状态只能修改一次
              如果executor内部出错了,promise状态改成rejected
        3. then方法的实现
          promise.then(onResolved, onRejected)      
            promise的状态是resolved时,异步调用onResolved函数
            promise的状态是rejected时,异步调用onRejected函数
            promise的状态是pending时,不调用函数。
              未来promise可能会变化,此时还是要异步调用相应的函数
        4. promise.then().then()  
          then方法返回值是promise,才能链式调用
          返回值promise对象的状态:
            1. 如果内部没有返回值 / 返回值不是promise 就是resolved
            2. 如果内部返回值是promise 看promise的状态
            3. 如果内部抛异常,就是rejected    
    */
    function MyPromise(executor) {
      // 初始化promise实例对象状态
      this._status = 'pending';
      // 初始化promise实例对象结果值
      this._value = undefined;
      // 初始化存储 回调函数 的容器
      this._callbacks = {};
      // 缓存this --> promise实例对象
      const _that = this;
      try {
        // 放置可能出错代码
        // 一旦try里面代码出错了,就会中断try中代码运行,直接来到catch
        // 执行MyPromise构造函数,要立即执行executor
        executor(resolve, reject);
      } catch (e) {
        // 来到catch,说明executor函数内部出错了~
        // 将promise对象状态改成rejected
        reject(e);
      }
      // 定义resolve
      function resolve(value) {
        // 状态只能修改一次
        if (_that._status === 'pending') {
          // 调用resolve方法将promise对象状态改成resolved状态
          _that._status = 'resolved';
          _that._value = value;
          // 异步调用onResolved函数
          if (_that._callbacks.onResolved) {
            setTimeout(() => {
              _that._callbacks.onResolved(value)
            })
          }
        }
      }
      // 定义reject
      function reject(reason) {
        if (_that._status === 'pending') {
          // 调用reject方法将promise对象状态改成rejected状态
          _that._status = 'rejected';
          _that._value = reason;
          // 异步调用onRejected函数
          if (_that._callbacks.onRejected) {
            setTimeout(() => {
              _that._callbacks.onRejected(reason)
            })
          }
        }
      }
    }
    MyPromise.prototype.then = function (onResolved, onRejected) {
      const _that = this;
      // 如果onResolved存在,不变
      // 如果onResolved不存在,说明catch触发的。 如果是成功状态promise,保证返回值还是一个成功状态promise
      onResolved = onResolved ? onResolved : (value) => value;
      // then方法一旦只传一个参数,并且是失败状态promise,保证返回值 是 失败状态promise内部的值
      onRejected = onRejected ? onRejected : (reason) => {
        throw reason
      };
      // 为了将来作为promise对象使用
      let promise = null;
      // this指向promise实例对象
      if (this._status === 'resolved') {
        // 说明promise对象的状态是resolved
        // 异步调用onResolved函数
        promise = new MyPromise(function (resolve, reject) {
          setTimeout(() => {
            doResolve(onResolved, _that._value, resolve, reject);
          })
        })
      } else if (this._status === 'rejected') {
        promise = new MyPromise(function (resolve, reject) {
          setTimeout(() => {
            doResolve(onRejected, _that._value, resolve, reject);
          })
        })
      } else {
        // 说明promise对象的状态是pending状态
        // 将回调函数存在this上
        promise = new MyPromise(function (resolve, reject) {
          // _that是p1, 外面promise是p2
          // p1调用onResolved/onRejected回调时,要更新p2的状态
          _that._callbacks.onResolved = function (value) {
            doResolve(onResolved, value, resolve, reject);
          };
          _that._callbacks.onRejected = function (reason) {
            doResolve(onRejected, reason, resolve, reject);
          };
        })
      }
      // 为了链式调用
      return promise;
    }
    // 定义函数复用代码
    function doResolve(onFn, value, resolve, reject) {
      try {
        const result = onFn(value);
        if (result instanceof MyPromise) {
          result.then(resolve, reject)
        } else {
          resolve(result);
        }
      } catch (e) {
        reject(e);
      }
    }
    MyPromise.prototype.catch = function (onRejected) {
      return this.then(undefined, onRejected);
    }
    MyPromise.prototype.finally = function (onResolved) {
      const _that = this;
      return new Promise((resolve, reject) => {
        if (_that._status === 'pending') {
          const callback = function (value) {
            doResolve(onResolved, value, resolve, reject)
          };
          _that._callbacks.onResolved = callback;
          _that._callbacks.onRejected = callback;
        } else {
          doResolve(onResolved, _that._value, resolve, reject);
        }
      })
    }
    // 返回一个成功状态promise
    MyPromise.resolve = function (value) {
      return new MyPromise((resolve, reject) => {
        resolve(value);
      })
    }
    // 返回一个失败状态promise
    MyPromise.reject = function (reason) {
      return new MyPromise((resolve, reject) => {
        reject(reason);
      })
    }
    // 接受一个数组(数组中放置n个promise对象),只有所有promise对象都成成功状态,方法返回值的promise才是成功
    // 只要有一个失败,方法返回值的promise就失败
    MyPromise.all = function (promises) {
      // promises的长度
      const promiseLength = promises.length;
      // 定义标识变量: promise对象成功的数量
      let resolvedCount = 0;
      // 成功的结果值
      const resolvedValues = [];
      return new MyPromise((resolve, reject) => {
        for (let i = 0; i < promiseLength; i++) {
          const promise = promises[i];
          // 看promise的状态
          promise.then((value) => {
            resolvedCount++;
            // 不能用push,输出顺序会乱
            // 使用下标,才能保证顺序ok
            resolvedValues[i] = value;
            if (resolvedCount === promiseLength) {
              // 说明都成功了
              resolve(resolvedValues);
            }
          }, reject)
        }
      })
    }
    const promise = new MyPromise((resolve, reject) => {
      console.log('executor函数执行了~');
      setTimeout(() => {
        // resolve(111);
        reject(222);
      }, 2000)
    })
    promise
      .then(() => {
        console.log(111);
        // 当then方法没有传入第二个回调。
        // 那么一旦接受的promise对象的状态是失败状态,返回值也是失败状态
      })
      .catch((reason) => {
        console.log(222, reason);
        // return Promise.reject();
        // throw new Error(111)
        return 333;
      })
      .then((value) => {
        console.log(333, value);
      })
      .catch(() => {
        console.log(444);
      })

用js实现promise的更多相关文章

  1. 关于学习js的Promise的心得体会

    最近一直在研究js的Promise对象,其中有一篇blog写得比较通俗易懂,转发如下: http://www.cnblogs.com/lvdabao/p/es6-promise-1.html 参照上面 ...

  2. js的Promise学习笔记(1)

    1: 何为Promise Promise是抽象异步处理对象以及对其对象进行各种操作的组件,是基于并列/并行处理设计的一种编程语言. 说到基于JavaScript的异步处理,大多数都会想到利用回调函数. ...

  3. 讲解JS的promise,这篇是专业认真的!

    http://www.zhangxinxu.com/wordpress/2014/02/es6-javascript-promise-%E6%84%9F%E6%80%A7%E8%AE%A4%E7%9F ...

  4. Angular JS中 Promise用法

    一.Promise形象讲解A promise不是angular首创的,作为一种编程模式,它出现在1976年,比js还要古老得多.promise全称是 Futures and promises. 而在j ...

  5. Node.js之Promise维护(同步)多个回调(异步)状态

    金天:学习一个新东西,就要持有拥抱的心态,如果固守在自己先前的概念体系,就会有举步维艰的感觉..NET程序员初用node.js最需要适应的就是异步开发, 全是异步,常规逻辑下遍历列表都是异步,如何保证 ...

  6. Node.js之Promise

    2015年发布了ES6标准,所谓 Promise,就是ES6标准的一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步 ...

  7. JS 中Promise 模式

    异步模式在web编程中变得越来越重要,对于web主流语言Javscript来说,这种模式实现起来不是很利索,为此,许多Javascript库(比如 jQuery和Dojo)添加了一种称为promise ...

  8. 7月22日-奇舞团关于when.js与promise的分享

    关于when.js的使用见屈屈的分享 http://www.imququ.com/post/promises-when-js.html 关于promise的实现见月影的分享 http://www.wu ...

  9. node.js的Promise库-bluebird示例

    前两天公司一哥们写了一段node.js代码发给我,后面特意提了一句“写的不太优雅”.我知道,他意思是回调嵌套回调,因为当时比较急也就没有再纠结.然而内心中总记得要解决这个问题.解决node.js的回调 ...

  10. 在Node.js使用Promise的方式操作Mysql(续)

    在之后的开发中,为了做一些事务开发,我把mysql的连接代码从之前的query函数中分离出来了,直接使用原生的方法进行操作,但发现还是有点问题 原因是原生的node-mysql采用了回调函数的方式,同 ...

随机推荐

  1. Django REST framework版本控制

    参考链接:https://www.cnblogs.com/liwenzhou/p/10269268.html 1.路由: #版本控制 re_path('^(?P<version>[v1|v ...

  2. 2019-2020-1 20199302《Linux内核原理与分析》第七周作业

    第六章 进程的描述和进程的创建 (一)进程的描述 1.OS的三大管理功能:(1)进程管理(进程)(2)内存管理(虚拟内存)(3)文件系统(文件) 2.进程的描述:进程控制块PCB 3.在Linux内核 ...

  3. 数论--扩展欧几里得exgcd

    算法思想 我们想求得一组\(x,y\)使得 \(ax+by = \gcd(a,b)\) 根据 \(\gcd(a,b) = \gcd(b,a\bmod b)\) 如果我们现在有\(x',y'\) 使得 ...

  4. 手工部署yugabyte的几点说明

    ntp 时间同步 ntp 时间同步对于yugabyte 是一个比较重要的服务,需要注意时间的同步 YB-Master 个数的说明 原则 YB-Master 的个数,必须和复制因子的个数一样,同时mas ...

  5. 21-ESP8266 SDK开发基础入门篇--C# TCP客户端 , 控制LED亮灭

    https://www.cnblogs.com/yangfengwu/p/11192603.html 由于是台式机,,没有插无线网卡...所以呢我就用调试助手监控下数据 后期让WIFI连接路由器的时候 ...

  6. 【JZOJ6228】【20190621】ni

    题目 $ n $ 个数 $ E_i $ ,$ F(i) $ 表示对1-i的数任意排列 $ p $ ,初始 $ X=0 $ ,依次执行: \(X \lt E_{p_j} \ , \ X++\) $X \ ...

  7. 计蒜客 39268.Tasks-签到 (The 2019 ACM-ICPC China Shannxi Provincial Programming Contest A.) 2019ICPC西安邀请赛现场赛重现赛

    Tasks It's too late now, but you still have too much work to do. There are nn tasks on your list. Th ...

  8. PHP 之根据两个经纬度计算距离

    一.函数代码 /** * @param $lng1 * @param $lat1 * @param $lng2 * @param $lat2 * @return float */ function g ...

  9. 关于Java正则和转义中\\和\\\\的理解

    定义 一个转义字符的目的是开始一个字符序列,使得转义字符开头的该字符序列具有不同于该字符序列单独出现时的语义. 转义就是指转换该字符的原本意义,从而变成另外的意义. \作为Java的转义字符 1.在j ...

  10. magento2重写virtualType并且传参

    今天遇到一个需求需要重写一个block,但是这个block是应用virtualType实现,所以需要先重写virtualType,然后却因为参数丢失而获取不到正确的结果.因此,查阅文档,需要用type ...