/*
      自定义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. SQL查询结果拼接成字符串

    sqlserver中将查询结果拼接成字符串   #for xml path(param)--将查询结果以xml格式输出 1 select id,name from table1 for xml pat ...

  2. redis node 常用命令

    命令窗口 flushall //清空全库 keys * //查看所有 HMSET user1 name liujinyu age 25 //哈希 添加多个值 HSET user1 sex man // ...

  3. lis框架showoncodename的用法

    fm.Sex.value=tContent2[0][3];//这个一定得是查询出来的码值alert("获取到的值是:"+tContent2[0][3]);showOneCodeNa ...

  4. 4、NameNode启动过程详解

    NameNode 内存 本地磁盘 fsimage edits 第一次启动HDFS 格式化HDFS,目的就是生成fsimage start NameNode,读取fsimage文件 start Data ...

  5. 自定义注解-aop实现日志记录

    关于注解,平时接触的可不少,像是 @Controller.@Service.@Autowried 等等,不知道你是否有过这种疑惑,使用 @Service 注解的类成为我们的业务类,使用 @Contro ...

  6. BZOJ 4197: [Noi2015]寿司晚宴 状压dp+质因数分解

    挺神的一道题 ~ 由于两个人选的数字不能有互质的情况,所以说对于一个质因子来说,如果 1 选了,则 2 不能选任何整除该质因子的数. 然后,我们发现对于 1 ~ 500 的数字来说,只可能有一个大于 ...

  7. 55、Spark Streaming:updateStateByKey以及基于缓存的实时wordcount程序

    一.updateStateByKey 1.概述 SparkStreaming 7*24 小时不间断的运行,有时需要管理一些状态,比如wordCount,每个batch的数据不是独立的而是需要累加的,这 ...

  8. [转]gulp排除已压缩文件思路

    文章转载至[gulp排除已压缩文件思路] gulp默认排除语法的弊端 有个时候我们需要时用gulp排除已经压缩过的js,css等.如果以压缩文件是以".min.js"之类命名规范的 ...

  9. 前端微信小程序生鲜类仿爱鲜蜂微信小程序

    需求描述及交互分析设计思路和相关知识点首页界面布局设计闪送超市纵向导航设计商品添加到购物车设计购物车商品显示设计收货地址列表显示设计新增收货地址设计 交互分析(1)底部标签导航有首页.闪送超市.购物车 ...

  10. CNN中各类卷积总结:残差、shuffle、空洞卷积、变形卷积核、可分离卷积等

    CNN从2012年的AlexNet发展至今,科学家们发明出各种各样的CNN模型,一个比一个深,一个比一个准确,一个比一个轻量.我下面会对近几年一些具有变革性的工作进行简单盘点,从这些充满革新性的工作中 ...