道可道,非常道——详解promise

Posted mzqn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了道可道,非常道——详解promise相关的知识,希望对你有一定的参考价值。

  promise 出来已久,以前一直使用,没有仔细剖析原理,最近在复习es6的知识,写一下自己对于promise的理解。

  promise是es6的一种异步编程解决方案,避免频繁的回调函数,增强代码的可阅读性。

  写法很简单:   

    let p2 = new Promise((reslove, reject) => {
      reslove(1)
    })
    
    console.log(p2.then(res => {
      alert(res)
    }))

  Promise是内置的构造函数,reslove、reject是固定的,只能这么写。reslove()表示成功,reject()表示失败。

  方法:

  1. then()   then是Promise的核心方法,是用来获取异步的返回结果。有两个参数用来获取reslove 或 reject 的值。
  2. catch()  用来捕获异常。
  3. all() 多个promise,所有的参与的promise对象全部执行完才会出结果。参数为类数组对象。
  4. race() 参数为类数组对象,任何一个参与的promise对象执行完,就会出结果。

  以上为常用的四个方法。

  代码:

  

/*
    *
    *   promise
    *   异步编程的一种解决方案。
    *
    * */
    const promise = new Promise(function (reslove, reject) {
        console.log(‘开始‘)
        setTimeout(function () {
           reslove(2)
        }, 3000)
    })

    promise.then(function (value) {
      return 3;
    }).then(function (value) {

    })

    //
    let p = new Promise((reslove, reject) => {
      setTimeout(()=>{
         let a = Math.random();
        if (a>0.5) {
          //reslove(a); // 这里说白了是就是调用下面的then中的函数 a
          reslove.call(null, a) // 这样也行
        } else {

          reject(a) // 调用b
        }
         reject(a) // 调用b
      }, 1000)
    })

    p.then(res => { // 假设这是函数a
      return res;
    }, rej => { // 函数b
      return rej;
    }).then(success => { // 链式调用的重点是前边的then必须return 否则 为undefined
      return success;
    }, fail => {
      return fail;
    })

    // then() then方法是挂在Promise.prototype上的
    console.log(Promise.prototype) // Promise {constructor: ?, then: ?, catch: ?, finally: ?, Symbol(Symbol.toStringTag): "Promise"}

    // catch() 相当于 then(null, reject)
   p.then(rel => {
     console.log(rel)
     return rel;
   },rej => {
     console.log(rej + ‘小‘)
     return rej;
   }).then(rel => { // 前一个then返回成功或失败都在这里  因为执行catch()后返回一个新的实例该实例该实例执行完之后会变为reslove ,因此后边的catch始终执行不到
     console.log(rel)
     alert(2)
   }).catch(rej => { // 这句是走不到的
     console.log(rej)
     alert(1)
     console.log(‘二小‘)
   })

   // finally() 状态成功或失败 都会执行此操作
   let p1 = new Promise((reslove, reject) => {
     console.log(this) // window 箭头函数本身没有this 因此this指向定义箭头函数时的上下文
     reslove(1);
   })

   p1.then(res => {
     console.log(‘success‘)
   }).finally(res => {
     console.log(‘finally‘)
   })

   // all() 所有实例的状态都改变完才改变
   let p2 = new Promise((reslove, reject) => {
     setTimeout(() => {
       alert(1)
       reslove(1)
     } ,1000)
   })

   let p3 = new Promise((reslove, reject) => {
     setTimeout(() => {
       alert(2)
       reslove(2)
     } ,2000)
   })

   let p4 = new Promise((reslove, reject) => {
     setTimeout(() => {
       alert(3)
       reject(3)
     } ,3000)
   })
   Promise.all([p2, p3]).then(res => {
     console.log(res) // [1, 2]
   })


   Promise.all([p2, p3, p4]).then(res => {
     console.log(res)
   }).catch(rej => {
     console.log(rej) // 3  只要有一个reject 就走这里 不走上边的then 返回的永远是第一个reject的promise实例
   })
   // race()
  Promise.race([p2, p3]).then(res => {
    console.log(res) // 1
  })

  下面是手写的实现promise的原理:

  

// 实现 promise
   function MyPromise(fn){ // fn 为 new Promise(fn)
     let _this = this;
     _this.status = ‘pending‘;
     _this.resloveValue = null; // 成功时的数据
     _this.rejectValue = null; // 失败时的数据
     _this.resloveFnCallbacks = [];
     _this.rejectFnCallbacks = [];

     function reslove(value) {
       if (_this.status == ‘pending‘) {
            _this.status = ‘resloved‘;
            _this.resloveValue = value;
            _this.resloveFnCallbacks.forEach(fn => fn())
       }
     }
     function reject(value) {
       if (_this.status == ‘pending‘) {
            _this.status = ‘rejected‘;
            _this.rejectValue = value;
            _this.rejectFnCallbacks.forEach(fn => fn())
       }

    }
     // 捕获异常
     try{
        fn(reslove, reject)
     } catch (e) {
       reject(e)
     }

    }

    // then() 应该接受两个参数 成功 或 失败的 回调
    MyPromise.prototype.then = function (resloveFn, rejectFn) {
      let _this = this;
      let promise2; // then 返回的promise

      // 参数非函数转为函数
      resloveFn = typeof resloveFn === ‘function‘? resloveFn: (function (value) {
        return value;
      })

      rejectFn = typeof rejectFn === ‘function‘? rejectFn: function (err) {
        throw err;
      }

      if(this.status == ‘resloved‘) { // 成功
        alert(3)
        promise2 =  new MyPromise((reslove, reject) => {
          setTimeout(() => {
            let x = resloveFn(this.resloveValue);
            resolvePromise(promise2, x, reslove, reject);
          })
        })
      }

      if(this.status == ‘rejected‘) { // 失败
        rejectFn(this.rejectValue)
      }

      if (this.status == ‘pending‘) {
        this.resloveFnCallbacks.push(function(){
          resloveFn(_this.resloveValue)
        })
        this.rejectFnCallbacks.push(function(){
          rejectFn(_this.rejectValue)
        })
      }

      return promise2;

      // resolvePromise
      function resolvePromise(promise2, x, reslove, reject) {
        let called; // 是否调用过

        // 判断上一次then返回的值 实质上下一个then只需要一个值便可以,所以我们就是要将上一个的peomise中的值提取出来
        // then 返回promise只是为了链式调用,then本身需要一个实际的值,并不需要promise
        if (x != null && (typeof x === ‘object‘ || typeof x === ‘function‘)) {
          try {
              let then = x.then; // 保存x的then方法 这种是x是对象
              if (typeof then === ‘function‘) {
                then.call(x, function (y) {
                  if (called) return;
                  called = true;
                  resolvePromise(promise2, y, reslove, reject)
                }, function (rej) {
                  if (called) return;
                  called = true;
                  reject(rej)

                })
              } else { // x 是普通对象直接返回就行
                reslove(x);
              }
          } catch (e) {
            if (called) return;
            called = true;
            reject(e)
          }
        } else { // x 是普通值
          reslove(x)
        }
      }


    }

    // 将promise
    let p6 = new MyPromise(function(reslove, reject) {
      reslove(2)
    })
    p6.then(function(res){
        return res;
    }).then(function(res){
      alert(res)
    })

  参考链接:https://juejin.im/post/5ab20c58f265da23a228fe0f

 

以上是关于道可道,非常道——详解promise的主要内容,如果未能解决你的问题,请参考以下文章

天地之始,万物之母

融合

《道德经》全文

《道德经》全文

JavaScript 闭包

开篇第一篇