zoukankan      html  css  js  c++  java
  • 手写 promise

    1.首先申明Promise , promise 是一个类,接收一个函数作为参数,函数中会接收两个参数,一个是成功的回调 resolve,一个是失败的回调 reject, 在new 该类的的时候,传入的函数会立即执行

     1 class Promise {
     2   constructor(task){
     3     let resolve = () => {
     4 
     5     }
     6     let reject = () => {
     7 
     8     }
     9     task(resolve,reject)
    10   }
    11 }

    2.解决基本状态,promise有三个状态  pending, fulfilled, rejected

    pending为初始态,可以转为 fulfilled 成功态   也可以转为 rejected 失败态

    fulfilled 成功态  不可以转为其他状态  并且有一个返回值 value

    rejected 失败态  不可以转为其他状态 并且有一个错误返回值  reason

    如果任务函数报错 直接执行 reject

     1 class Promise2 {
     2   constructor(task){
     3     this.status = 'pending'
     4     this.value = undefined
     5     this.reason = undefined
     6     let resolve = value => {
     7       if(this.status === 'pending'){
     8         this.status = 'fulfilled'
     9         this.value = value
    10       }
    11     }
    12     let reject = reason => {
    13       if(this.status === 'pending'){
    14         this.status = 'rejected'
    15         this.reason = reason
    16       }
    17     }
    18     try{
    19       task(resolve,reject)
    20     }catch(err){
    21       reject(err)
    22     }
    23   }
    24 }

    3.then方法

    在promise 中有个then 的方法,里面有两个参数 onFulfilled,onRejected,成功有成功的值  失败有失败的原因

    当状态值是 fulfilled 的时候 执行 onFulfilled 函数并传入 this.value .当状态值是rejected 的时候 执行onRejected 函数并且传入this.reason

    如果 onFulfilled onRejected 是函数,必须在 fulfilled 和 rejected 后调用  并且第一个参数 分别是 this.value 和 this.reason

     1 class Promise2 {
     2   constructor(task){
     3     this.status = 'pending'
     4     this.value = undefined
     5     this.reason = undefined
     6     let resolve = value => {
     7       if(this.status === 'pending'){
     8         this.status = 'fulfilled'
     9         this.value = value
    10       }
    11     }
    12     let reject = reason => {
    13       if(this.status === 'pending'){
    14         this.status = 'rejected'
    15         this.reason = reason
    16       }
    17     }
    18     try{
    19       task(resolve,reject)
    20     }catch(err){
    21       reject(err)
    22     }
    23   }
    24   then(onFulfilled,onRejected){
    25     if(this.status === 'fulfilled'){
    26       onFulfilled(this.value)
    27     }
    28     if(this.status === 'rejected'){
    29       onRejected(this.reason)
    30     }
    31   }
    32 }

    4.解决异步的问题

    上面基本可以解决一些同步的代码,但是当resolve 在setTimeout 中执行的时候,then 的时候的status 还是pending 状态,那么我们需要在then 的时候将成功和失败的函数存起来,在resolve 或者reject 的时候去调用

    类似于发布订阅模式 先将函数存在起来  而且可能会有多个then 函数 所有将成功和失败的函数分别存在 两个数组中 成功或者失败的时候用forEach 去调用

     1 class Promise2 {
     2   constructor(task){
     3     this.status = 'pending'
     4     this.value = undefined
     5     this.reason = undefined
     6     // 成功的回调函数存放数组
     7     this.onFulfilledCallbacks = []
     8     // 失败的函数回调存放数组
     9     this.onRejectedCallbacks = [] 
    10     let resolve = value => {
    11       if(this.status === 'pending'){
    12         this.status = 'fulfilled'
    13         this.value = value;
    14         // resolve 执行后调用成功回调函数
    15         this.onFulfilledCallbacks.forEach(fn => fn())
    16       }
    17     }
    18     let reject = reason => {
    19       if(this.status === 'pending'){
    20         this.status = 'rejected'
    21         this.reason = reason
    22         // reject 执行后调用失败回调函数
    23         this.onRejectedCallbacks.forEach(fn => fn())
    24       }
    25     }
    26     try{
    27       task(resolve,reject)
    28     }catch(err){
    29       reject(err)
    30     }
    31   }
    32   then(onFulfilled,onRejected){
    33     if(this.status === 'fulfilled'){
    34       onFulfilled(this.value)
    35     }
    36     if(this.status === 'rejected'){
    37       onRejected(this.reason)
    38     }
    39     if (this.status === 'pending'){
    40       this.onFulfilledCallbacks.push(onFulfilled(this.value))
    41       this.onRejectedCallbacks.push(onRejected(this.reason))
    42     }
    43   }
    44 }

    5.解决链式调用的问题

    我们常常这样用  new Promise().then().then() 来解决回调地狱的问题

    1.为了达成链式调用 在then 函数中返回 一个新的promise,我们这叫 promise2  = new Promise(function(resolve,reject){})

    2.将promise2 中的返回值传递给后面的then方法

    3.如果返回的是一个普通值 也传递给后面的then 方法中

    4.按规范 onFulfilled() 或者 onRejected()即第一个then 的返回值 我们叫 x ,判断x 的函数我们叫 resolvePromise

     在resolvePromise 中首先要看x 是不是Promise

    如果是Promise 就取他的结果 作为新的promise2 的成功的结果

    如果是成功的值 直接作为promise2 的成功的结果

    resolevePromise 的参数有 promise2 这个是默认返回的promise  x 是我们自己返回的对象  还要 resolve,reject  是promise2 的

     1 class Promise2 {
     2   constructor(task){
     3     this.status = 'pending'
     4     this.value = undefined
     5     this.reason = undefined
     6     // 成功的回调函数存放数组
     7     this.onFulfilledCallbacks = []
     8     // 失败的函数回调存放数组
     9     this.onRejectedCallbacks = [] 
    10     let resolve = value => {
    11       if(this.status === 'pending'){
    12         this.status = 'fulfilled'
    13         this.value = value;
    14         // resolve 执行后调用成功回调函数
    15         this.onFulfilledCallbacks.forEach(fn => fn())
    16       }
    17     }
    18     let reject = reason => {
    19       if(this.status === 'pending'){
    20         this.status = 'rejected'
    21         this.reason = reason
    22         // reject 执行后调用失败回调函数
    23         this.onRejectedCallbacks.forEach(fn => fn())
    24       }
    25     }
    26     try{
    27       task(resolve,reject)
    28     }catch(err){
    29       reject(err)
    30     }
    31   }
    32   then(onFulfilled,onRejected){
    33     let promise2 = new Promise2((resolve,reject) =>{
    34       if(this.status === 'fulfilled'){
    35         let x = onFulfilled(this.value)
    36         resolvePromise(promise2,x,resolve,reject)
    37       }
    38       if(this.status === 'rejected'){
    39        let x = onRejected(this.reason)
    40        resolvePromise(promise2,x,resolve,reject)
    41       }
    42       if (this.status === 'pending'){
    43         this.onFulfilledCallbacks.push(() =>{
    44           let x = onFulfilled(this.value)
    45           resolvePromise(promise2,x,resolve,reject)
    46         })
    47         this.onRejectedCallbacks.push(() => {
    48           let x = onRejected(this.reason)
    49           resolvePromise(promise2,x,resolve,reject)
    50         })
    51       }
    52     })
    53     return promise2
    54     
    55   }
    56 }

    6.我们在来完成 resolvePromise 函数

    让不同的promise代码互相套用,叫做resolvePromise

    • 如果 x === promise2,则是会造成循环引用,自己等待自己完成,则报“循环引用”错误

    比如

    1 let p = new Promsie((resolve) => {
    2    resolve(0) 
    3 })
    4 let p2 = p.then(data => {
    5   return p2       
    6 )

    先判断x

    如果   if x is an object or function,Let then be x.then

    x不能是 null 

    x是普通值 直接 resolve(x)

    x是对象或者函数的时候  let then = x.then

    如果取then 报错  直接走 reject()

    如果then是个函数,则用call执行then,第一个参数是this,后面是成功的回调和失败的回调

    如果成功的回调还是pormise,就递归继续解析

    成功和失败只能调用一个 所以设定一个called来防止多次调用

    function resolvePromise(promise2, x, resolve, reject){ 
        // 循环引用报错  
         if(x === promise2){     
           // reject报错   
             return reject(new TypeError('Chaining cycle detected for promise'));  
         }  
           // 防止多次调用 
        let called;   // x不是null 且x是对象或者函数 
        if (x != null && (typeof x === 'object' || typeof x === 'function')) {    
           try {       // A+规定,声明then = x的then方法     
              let then = x.then;       // 如果then是函数,就默认是promise了   
              if (typeof then === 'function') {          // 就让then执行 第一个参数是this   后面是成功的回调 和 失败的回调      
                   then.call(x, y => {   
                      // 成功和失败只能调用一个     
                      if (called) return;   
                      called = true;      
                  
                  // resolve的结果依旧是promise 那就继续解析    
                     resolvePromise(promise2, y, resolve, reject);         
                   }, err => {      
                 // 成功和失败只能调用一个    
                  if (called) return;       
                      called = true;     
                      reject(err);// 失败了就失败了    
                  })  
              }  else { 
                  resolve(x); // 直接成功即可    
                }   
            } catch (e) {     
                // 也属于失败    
                   if (called) return;   
                    called = true;      
                     // 取then出错了那就不要在继续执行了  
                   reject(e);     
               } 
          } else {     resolve(x);   } }
  • 相关阅读:
    TransmitFile
    xml
    鼠标划过表格行变色-简洁实现
    关于表变量
    显式接口成员实现
    华为致新员工书
    C#实现的堆栈
    Gridview中合并单元格,某字段的内容相同时如何只显示一个,屏蔽相同列或行的内容(转)
    ASP.NET 验证控件
    动态SQL EXEC
  • 原文地址:https://www.cnblogs.com/buxiugangzi/p/11689824.html
Copyright © 2011-2022 走看看