promise-3.md

自定义promise

开始之前,先来回顾一下JS中的闭包

JS特殊的作用域

变量的作用域无非就是两种:全局变量局部变量,Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量函数外部自然无法读取函数内的局部变量(父对象的所有变量,对子对象都是可见的,反之则不成立)

就像下面的这个例子一样,在f2()中可以访问到f1()的n=999,但在f1()中是获取不到f2()中的m=888

function f1(){
  var n=999;
  function f2(){
  		var m = 888;
    alert(n); // 999
  }
}

要解决在f1()中可以获取到f2()中的值或者在f1()的外部获取到f2()中的值,只要把f2()作为返回值,就可以在f1()外部读取它的内部变量了~

function f1(){
  var n=999;
  function f2(){
    alert(n);
  }
  return f2;
}
var result=f1();
result(); // 999
闭包

所以!!上面说的f2()就是闭包(闭包就是能够读取其他函数内部变量的函数

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁

闭包可以用在许多地方。它的最大用处有两个:

  • 一个是前面提到的可以读取函数内部的变量
  • 另一个就是让这些变量的值始终保持在内存中

看代码理解

function f1(){
   var n=999;
   nAdd=function(){n+=1}
   function f2(){
    alert(n);
   }
   return f2;
  }
 var result=f1();
 result(); // 999
 nAdd();
 result(); // 1000

在这段代码中,result实际上就是闭包f2()。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,f1()中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除

原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收

f2被赋给了一个全局变量 ❓❓

"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作

自定义promise整体结构

  • 先创建一个lib/promise.js
// 自定义promise函数模块:IIFE

// 最外层的是匿名函数的自调用
// (function (params) {})()

(function (window) {
  /**
   Promise构造函数 
   executor:执行器构造函数(同步执行) 
   */
  function Promise(excutor) {
  	function resolve(){},
  	function reason(){},
  	
	// 立即同步执行excutor(执行器函数)
	excutor(resolve, reject);
  }


  /**
   * Promise原型对象的then()方法
   * 指定成功/失败的回调函数
   * 函数的返回值为一个新的promise对象
   */
  Promise.prototype.then = function (onResolved, onRejected) {
    
  }

  /**
   * Promise原型对象的catch()方法
   * 指定失败的回调函数
   * 函数的返回值为一个新的promise对象
   */
  Promise.prototype.catch = function (onRejected) {

  }

  /**
   * Promise函数对象的resolve方法
   * 返回一个指定结果的成功的promise
   */
  Promise.resolve = function (value) {

  }

  /**
   * Promise函数对象的reject方法
   * 返回一个指定reason的失败的promise
   */
  // 
  Promise.reject = function (reason) {

  }

  /**
   * Promise函数对象的all方法
   * 返回一个promise,只有当所有的promise都成功时才成功,否则失败
   */
  Promise.all = function (promises) {

  }


  /**
   * Promise函数对象的race方法
   * 返回一个promise,其结果由第一个完成的promise来决定
   */
  Promise.race = function (promises) {

  }


  // 向外暴露的Promise函数
  window.Promise = Promise;
})(window)
  • 在html中引入promise.js
<body>
  <script src="./lib/promise.js"></script>
  <script>
    const p = new Promise((resolve, reject) => {
       resolve(1); // 1 代表的是 value
      // reject(2); // 2 代表的是 reason
    )
  </script>
</body>

因为在html的promise中有resolve(value)reject(reason),所以在promise中的executor:执行器构造函数中也就应该有对应的参数

/**
Promise构造函数 
 executor:执行器构造函数(同步执行) 
 */
function Promise(excutor) {
	function resolve(value){},
	function reason(reason){}
}

接下来稍微完善一下excutor构造函数和html文件

/**
Promise构造函数 
 executor:执行器构造函数(同步执行) 
 */
function Promise(excutor) {
	this.status = 'pending'; //给promise对象指定status属性,初始值为pending
  	this.data = undefined; //给promise对象指定一个用于存储结果数据的属性
    this.callbacks = []; //每个元素的结构:{onResolved: {}, onRejected: {}}
    
	function resolve(value){},
	function reason(reason){}
}
<body>
  <script src="./lib/promise.js"></script>
  <script>
    const p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(1); // 1 代表的是 value
      // reject(2); // 2 代表的是 reason
      });
    })

    p.then(
      value => {},
      reason => {}
    )

    p.then(
      value => {},
      reason => {}
    )
  </script>
</body>

and then

如果执行html中的resolve的时候,js中的excutor构造函数得干嘛呢??

/**
   Promise构造函数 
   executor:执行器构造函数(同步执行) 
   */
  function Promise(excutor) {
    // 重定向this为_this, _this指的是Promise对象,不重定向的话this指的是window
    const _this = this;
    _this.status = 'pending'; //给promise对象指定status属性,初始值为pending
    _this.data = undefined; //给promise对象指定一个用于存储结果数据的属性
    _this.callbacks = []; //每个元素的结构:{onResolved: {}, onRejected: {}}

    function resolve(value) {
    // 这里判断如果当前状态不是pending,直接结束
      if(_this.status !== 'pending'){
        return;
      }

      // 将状态改为resolved
      _this.status = 'resolved'
      // 保存value数据
      _this.data = value;
      // 如果由待执行的callback函数,立即执行回调函数onResolved()
      if (_this.callbacks.length > 0) {
        setTimeout(() => { // 放入队列中所有成功的回调
          _this.callbacks.forEach(callbacksObj => {
            callbacksObj.onResolved(value);
          })
        }, 0);
      }
    }

    function reject(reason) {
    // 这里判断如果当前状态不是pending,直接结束
      if(_this.status !== 'pending'){
        return;
      }
      
      // 将状态改为rejected
      _this.status = 'rejected'
      // 保存value数据
      _this.data = reason;
      // 如果由待执行的callback函数,立即执行回调函数onResolved()
      if (_this.callbacks.length > 0) {
        setTimeout(() => { // 放入队列中所有失败的回调
          _this.callbacks.forEach(callbacksObj => {
            callbacksObj.onRejected(reason);
          })
        }, 0);
      }
    }


	// html如果在执行器中抛出异常的话,promise会变成失败状态,也就是即没调用resolve又没调用reject。执行器抛出异常想让Promise变成失败状态,就需要在js中 catch error 了
	
    // 立即同步执行excutor(执行器函数)
    try {
      excutor(resolve, reject);
    } catch (error) {   //如果执行器抛出异常,promise对象变为rejected状态
      return error;
    }
  }

然后在.then()函数中进行操作

Promise.prototype.then = function (onResolved, onRejected) {
    // 重定向this为_this, _this指的是Promise对象,不重定向的话this指的是window
    const _this = this;
    
    // 假设当前状态还是pending,将回调函数保存起来
    _this.callbacks.push({
      onResolved,
      onRejected
    })
  }

⚠️ 现在写的流程是先改状态,再指定回调函数。但是正常的流程是先执行回调函数再改状态。所以这里应该修改一下。给setTimeOut 加个延迟时间。然后可以在p.then()中打印一下

<body>
  <script src="./lib/promise.js"></script>
  <script>
    const p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(1); // 1 代表的是 value
      // reject(2); // 2 代表的是 reason

	 // 这里
      }, 100);
    })

    p.then(
      value => {
        console.log("onResolved1():", value);
      },
      reason => {
        console.log("onRejected1():", reason);
      }
    )

    p.then(
      value => {
        console.log("onResolved2():", value);
      },
      reason => {
        console.log("onRejected2():", reason);
      }
    )
  </script>
</body>

上面是resolve成功时的执行结果

还有一个就是来测试一下到底是同步调用还是异步调用

如果console.log("reject()改变状态之后");这句先执行,p.then()后执行,则可以说明回调函数是异步执行的

<body>
  <script src="./lib/promise.js"></script>
  <script>
    const p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(1); // 1 代表的是 value
      // reject(2); // 2 代表的是 reason

      // 用这个console.log来验证到底是同步还是异步
      console.log("reject()改变状态之后");
      }, 100);
    })

    p.then(
      value => {
        console.log("onResolved1():", value);
      },
      reason => {
        console.log("onRejected1():", reason);
      }
    )

    p.then(
      value => {
        console.log("onResolved2():", value);
      },
      reason => {
        console.log("onRejected2():", reason);
      }
    )
  </script>
</body>

怎么改状态,怎么存数据由内部定义者决定,什么时候调用由外部使用者决定

上面在.then()中直接是假设当前状态为pending的,但实际不一定是这样的,所以就需要在其中做状态的判断

这里先将状态定义成常量,是在(function (window) {下面直接定义的,然后将之前在各函数中的定义的状态都改成现在这样的大写形式

(function (window) {

  const PENDING = 'pending'
  const RESOLVED = 'resolved'
  const REJECTED = 'rejected'

  /**
   Promise构造函数 
   executor:执行器构造函数(同步执行) 
   */
  function Promise(excutor) {
  ...

修改完后在之前的.then方法中进行状态判断

 /**
   * Promise原型对象的then()方法
   * 指定成功/失败的回调函数
   * 函数的返回值为一个新的promise对象
   */
  Promise.prototype.then = function (onResolved, onRejected) {
    const _this = this;
    // 假设当前状态还是PENDiNG,将回调函数保存起来
    // 这里的this指的是promise对象

    if(_this.status === 'PENDING'){
      _this.callbacks.push({
        onResolved,
        onRejected
      })
    }else if (_this.status === 'RESOLVED'){
      setTimeout(() => {
        onResolved(_this.data);
      });
    }else {   // rejected
      setTimeout(() => {
        onRejected(_this.data);
      });
    }
  }

就像.then()函数上面的注释里面说的一样,最后结果是返回一个新的promise对象,所以这里应该return new Promise👇

 // 返回一个新的promise对象
 return new Promise ((resolve, reject) => {

 })

又因为这个Promise的参数中有 resolve 和 reject,如果你想在执行完函数之后根据结果去判断到底是调用resolve还是reject,这个时候就需要用上面的这个return语句将上面的状态判断包起来,然后在里面进行判断

/**
 * Promise原型对象的then()方法
  * 指定成功/失败的回调函数
  * 函数的返回值为一个新的promise对象
  */
 Promise.prototype.then = function (onResolved, onRejected) {
   const _this = this;
   // 假设当前状态还是PENDiNG,将回调函数保存起来
   // 这里的this指的是promise对象

   // 返回一个新的promise对象
   return new Promise((resolve, reject) => {
     if (_this.status === 'PENDING') {
       _this.callbacks.push({
         onResolved,
         onRejected
       })
     } else if (_this.status === 'RESOLVED') {
       setTimeout(() => {

         /**
          * 1. 如果抛出异常,return的Promise就会失败,reason就是error
          * 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
          * 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
          * 
          */

         try {
           const result = onResolved(_this.data);

           if (result instanceof Promise) {
             // 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
             result.then(
               value => resolve(value), // 当result成功时,让return 的 Promise 也成功
               reason => reject(reason) // 当result失败时,让return 的 Promise 也失败

               // 与下面写法一致
               // value => {
               //   resolve(value);
               // },
               // reason => {
               //   reject(reason);
               // }
             )
           } else {
             // 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
             resolve(result);
           }
           
         } catch (error) {
           // 1. 如果抛出异常,return的Promise就会失败,reason就是error
           reject(error);
         }

       });
     } else { // rejected
       setTimeout(() => {
         onRejected(_this.data);
       });
     }


   })

 }

接下来将上面else if 中的的写法更改成更简洁版

setTimeout(() => {

   /**
      * 1. 如果抛出异常,return的Promise就会失败,reason就是error
      * 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
      * 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
      * 
      */

     try {
       const result = onResolved(_this.data);

       if (result instanceof Promise) {
         // 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
         // result.then(
         //   value => resolve(value), // 当result成功时,让return 的 Promise 也成功
         //   reason => reject(reason) // 当result失败时,让return 的 Promise 也失败
         // )

         //  上面的写法和下面的是一样的
         
         // 说明
         // 假设result成功了,那它会调 resolve,并且给resolve传入成功的value
         // 那return 的 Promise 就会变成成功的状态
         result.then(resolve, reject);
       } else {
         // 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
         resolve(result);
       }
       
     } catch (error) {
       // 1. 如果抛出异常,return的Promise就会失败,reason就是error
       reject(error);
     }

   });

else if 中可以这样写的话,那么else 中也就可以这样写了,只是把之前的 onResolved() 改为 onRejected()

else { // rejected
setTimeout(() => {

  /**
   * 1. 如果抛出异常,return的Promise就会失败,reason就是error
   * 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
   * 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
   * 
   */

  try {
    const result = onRejected(_this.data);

    if (result instanceof Promise) {
      // 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
      // result.then(
      //   value => resolve(value), // 当result成功时,让return 的 Promise 也成功
      //   reason => reject(reason) // 当result失败时,让return 的 Promise 也失败
      // )

      //  上面的写法和下面的是一样的
      
      // 说明
      // 假设result成功了,那它会调 resolve,并且给resolve传入成功的value
      // 那return 的 Promise 就会变成成功的状态
      result.then(resolve, reject);
    } else {
      // 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
      resolve(result);
    }
    
  } catch (error) {
    // 1. 如果抛出异常,return的Promise就会失败,reason就是error
    reject(error);
  }

});
}

接下来

看一下.then函数里面的代码

如果当前是pending状态的时候,就直接_this.callbacks.push 存起来,而且如果成功了的话就会执行onResolved函数,如果失败了就执行onRejected。但问题是执行完它们之后,怎么影响这个Promise的状态呢??(可以看出直接将onResolvedonRejected存进callbacks中是不行的

 Promise.prototype.then = function (onResolved, onRejected) {
  const _this = this;
  // 假设当前状态还是PENDiNG,将回调函数保存起来
  // 这里的this指的是promise对象

  // 返回一个新的promise对象
  return new Promise((resolve, reject) => {
    if (_this.status === 'PENDING') {
      _this.callbacks.push({
        onResolved,
        onRejected
      })
    } else if (_this.status === 'RESOLVED') {
      setTimeout(() => {

        /**
         * 1. 如果抛出异常,return的Promise就会失败,reason就是error
         * 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
         * 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
         * 
         */

        try {
          const result = onResolved(_this.data);

          if (result instanceof Promise) {
            // 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
            // result.then(
            //   value => resolve(value), // 当result成功时,让return 的 Promise 也成功
            //   reason => reject(reason) // 当result失败时,让return 的 Promise 也失败
            // )

            //  上面的写法和下面的是一样的

            // 说明
            // 假设result成功了,那它会调 resolve,并且给resolve传入成功的value
            // 那return 的 Promise 就会变成成功的状态
            result.then(resolve, reject);
          } else {
            // 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
            resolve(result);
          }
          
        } catch (error) {
          // 1. 如果抛出异常,return的Promise就会失败,reason就是error
          reject(error);
        }

      });
    } else { // rejected
      setTimeout(() => {

        /**
         * 1. 如果抛出异常,return的Promise就会失败,reason就是error
         * 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
         * 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
         * 
         */

        try {
          const result = onRejected(_this.data);

          if (result instanceof Promise) {
            // 3. 如果回调函数返回的是Promise,return的promise的结果就是这个promise的结果
            // result.then(
            //   value => resolve(value), // 当result成功时,让return 的 Promise 也成功
            //   reason => reject(reason) // 当result失败时,让return 的 Promise 也失败
            // )

            //  上面的写法和下面的是一样的
            
            // 说明
            // 假设result成功了,那它会调 resolve,并且给resolve传入成功的value
            // 那return 的 Promise 就会变成成功的状态
            result.then(resolve, reject);
          } else {
            // 2. 如果回调函数返回的不是Promise,return的promise就会成功,value就是返回的值
            resolve(result);
          }
          
        } catch (error) {
          // 1. 如果抛出异常,return的Promise就会失败,reason就是error
          reject(error);
        }

      });
    }
  })
}

这块还没有完善好…

自定义resolve/reject


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值