成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

手寫一個(gè)PromiseA+的實(shí)現(xiàn)

suxier / 1388人閱讀

摘要:手寫一個(gè)的實(shí)現(xiàn)。當(dāng)注冊(cè)的回調(diào)函數(shù)返回的是的時(shí)候,從這個(gè)之后的所有的注冊(cè)函數(shù)都應(yīng)該注冊(cè)在新返回的上。直到遇到下一個(gè)回調(diào)函數(shù)的返回值也是。

Promise

手寫一個(gè)PromiseA+的實(shí)現(xiàn)。注意這里只是模擬,實(shí)際上原生的promise在事件隊(duì)列中屬于microTask。這里用setTimeout模擬不是特別恰當(dāng)。因?yàn)閟etTimeout是一個(gè)macroTask。

1. 最簡單的基本功能
/**
 * 定義Promise
 * 先實(shí)現(xiàn)一個(gè)最簡單的。用setTimeout模擬一個(gè)異步的請(qǐng)求。
 */
function Promise(fn){
  var value= null;
  var callbacks = [];
  this.then = function(onFulfilled) {
    callbacks.push(onFulfilled);
  }

  function resolve(value){
    callbacks.forEach(function(cb){
      cb(value);
    })
  }

  fn(resolve);
}


// 使用Promise
var p = new Promise(function(resolve){
  setTimeout(function(){
    resolve("這是響應(yīng)的數(shù)據(jù)")
  },2000)
})

p.then(function(response){
  console.log(response);
})
2.鏈?zhǔn)秸{(diào)用
/**
 * 先看一下前一個(gè)例子存在的問題
 * 1.在前一個(gè)例子中不斷調(diào)用then需要支持鏈?zhǔn)秸{(diào)用,每次執(zhí)行then都要返回調(diào)用對(duì)象本身。
 * 2.在前一個(gè)例子中,當(dāng)鏈?zhǔn)秸{(diào)用的時(shí)候,每次then中的值都是同一個(gè)值,這是有問題的。其實(shí)第一次then中的返回值,應(yīng)該是第二次調(diào)用then中的函數(shù)的參數(shù),依次類推。
 * 所以,我們進(jìn)一步優(yōu)化一下代碼。
 * 
 */
function Promise(fn){
  var value= null;
  var callbacks = [];
  this.then = function(onFulfilled) {
    callbacks.push({f:onFulfilled});
    return this;
  }

  function resolve(value){
    callbacks.map(function(cb,index){
      if(index === 0){
        callbacks[index].value = value;
      }
      var rsp = cb.f(cb.value);
      if(typeof callbacks[index+1] !== "undefined"){
        callbacks[index+1].value = rsp;
      }
    })
  }
  fn(resolve);
}


// 使用Promise
var p = new Promise(function(resolve){
  setTimeout(function(){
    resolve("這是響應(yīng)的數(shù)據(jù)")
  },2000)
})

p.then(function(response){
  console.log(response);
  return 1;
}).then(function(response){
  console.log(response);
  return 2;  
}).then(function(response){
  console.log(response);
})
3. 異步
/**
 * 先看一下前一個(gè)例子存在的問題
 * 1. 如果在then方法注冊(cè)回調(diào)之前,resolve函數(shù)就執(zhí)行了,怎么辦?比如 new Promise的時(shí)候傳入的函數(shù)是同步函數(shù)的話,
 * then還沒被注冊(cè),resolve就執(zhí)行了。。這在PromiseA+規(guī)范中是不允許的,規(guī)范明確要求回調(diào)需要通過異步的方式執(zhí)行。
 * 用來保證一致可靠的執(zhí)行順序。
 * 
 * 因此我們需要加入一些處理。把resolve里的代碼放到異步隊(duì)列中去。這里我們利用setTimeout來實(shí)現(xiàn)。
 * 原理就是通過setTimeout機(jī)制,將resolve中執(zhí)行回調(diào)的邏輯放置到JS任務(wù)隊(duì)列末尾,以保證在resolve執(zhí)行時(shí),
 * then方法的回調(diào)函數(shù)已經(jīng)注冊(cè)完成
 * 
 */
function Promise(fn){
  var value= null;
  var callbacks = [];
  this.then = function(onFulfilled) {
    callbacks.push({f:onFulfilled});
    return this;
  }

  function resolve(value){
    setTimeout(function(){
        callbacks.map(function(cb,index){
          if(index === 0){
            callbacks[index].value = value;
          }
          var rsp = cb.f(cb.value);
          if(typeof callbacks[index+1] !== "undefined"){
            callbacks[index+1].value = rsp;
          }
        })
    },0)
  }
  fn(resolve);
}


// 使用Promise,現(xiàn)在即使是同步的立馬resolve,也能正常運(yùn)行了。
var p = new Promise(function(resolve){
    resolve("這是響應(yīng)的數(shù)據(jù)")
})

p.then(function(response){
  console.log(response);
  return 1;
}).then(function(response){
  console.log(response);
  return 2;  
}).then(function(response){
  console.log(response);
})
4. 狀態(tài)機(jī)制
/**
 * 先看一下前一個(gè)例子存在的問題
 * 1.前一個(gè)例子還存在一些問題,如果Promise異步操作已經(jīng)成功,在這之前注冊(cè)的所有回調(diào)都會(huì)執(zhí)行,
 * 但是在這之后再注冊(cè)的回調(diào)函數(shù)就再也不執(zhí)行了。具體的運(yùn)行下面這段代碼,可以看到“can i invoke”并沒有打印出來
 * 想要解決這個(gè)問題,我們就需要加入狀態(tài)機(jī)制了。具體實(shí)現(xiàn)看本文件夾下的另一個(gè)js文件里的代碼。
 * 
 */
function Promise(fn){
  var value= null;
  var callbacks = [];
  this.then = function(onFulfilled) {
    callbacks.push({f:onFulfilled});
    return this;
  }

  function resolve(value){
    setTimeout(function(){
        callbacks.map(function(cb,index){
          if(index === 0){
            callbacks[index].value = value;
          }
          var rsp = cb.f(cb.value);
          if(typeof callbacks[index+1] !== "undefined"){
            callbacks[index+1].value = rsp;
          }
        })
    },0)
  }
  fn(resolve);
}


// 
var p = new Promise(function(resolve){
    resolve("這是響應(yīng)的數(shù)據(jù)")
})

p.then(function(response){
  console.log(response);
  return 1;
}).then(function(response){
  console.log(response);
  return 2;  
}).then(function(response){
  console.log(response);
})

setTimeout(function(){
   p.then(function(response){
     console.log("can i invoke?");
   })
},0)
/**
 * 在promise01.js中,我們已經(jīng)分析了,我們需要加入狀態(tài)機(jī)制
 * 在這里實(shí)現(xiàn)一下PromiseA+中關(guān)于狀態(tài)的規(guī)范。
 * 
 * Promises/A+規(guī)范中的2.1Promise States中明確規(guī)定了,pending可以轉(zhuǎn)化為fulfilled或rejected并且只能轉(zhuǎn)化一次,
 * 也就是說如果pending轉(zhuǎn)化到fulfilled狀態(tài),那么就不能再轉(zhuǎn)化到rejected。
 * 并且fulfilled和rejected狀態(tài)只能由pending轉(zhuǎn)化而來,兩者之間不能互相轉(zhuǎn)換
 * 
 */
function Promise(fn){
  var status = "pending"
  var value= null;
  var callbacks = [];
  this.then = function(onFulfilled) {
    // 如果是pending狀態(tài),則加入到注冊(cè)隊(duì)列中去。
    if(status === "pending"){
      callbacks.push({f:onFulfilled});
      return this;
    }
    // 如果是fulfilled 狀態(tài),此時(shí)直接執(zhí)行傳入的注冊(cè)函數(shù)即可。
    onFulfilled(value);
    return this;
  }

  function resolve(newValue){
    value = newValue;
    status = "fulfilled";
    setTimeout(function(){
        callbacks.map(function(cb,index){
          if(index === 0){
            callbacks[index].value = newValue;
          }
          var rsp = cb.f(cb.value);
          if(typeof callbacks[index+1] !== "undefined"){
            callbacks[index+1].value = rsp;
          }
        })
    },0)
  }
  fn(resolve);
}


// 
var p = new Promise(function(resolve){
    resolve("這是響應(yīng)的數(shù)據(jù)")
})

p.then(function(response){
  console.log(response);
  return 1;
}).then(function(response){
  console.log(response);
  return 2;  
}).then(function(response){
  console.log(response);
})

setTimeout(function(){
   p.then(function(response){
     console.log("can i invoke?");
   })
},1000)
/**
 * 剛才的例子中,確實(shí)打印出了 can i invoke,但是之前then的注冊(cè)函數(shù)的返回值,并沒有打印出來。
 * 也就是說 1 和 2 并沒有被打印出來,看下面的注釋
 * 
 */
function Promise(fn){
  var status = "pending"
  var value= null;
  var callbacks = [];
  this.then = function(onFulfilled) {

    if(status === "pending"){
      callbacks.push({f:onFulfilled});
      return this;
    }

    onFulfilled(value);
    return this;
  }

  function resolve(newValue){
    value = newValue;
    status = "fulfilled";
    setTimeout(function(){
        callbacks.map(function(cb,index){
          if(index === 0){
            callbacks[index].value = newValue;
          }
          var rsp = cb.f(cb.value);
          if(typeof callbacks[index+1] !== "undefined"){
            callbacks[index+1].value = rsp;
          }
        })
    },0)
  }
  fn(resolve);
}

var p = new Promise(function(resolve){
    resolve("aaaaaa")
})

p.then(function(response){
  console.log(response);    
  return 1;
}).then(function(response){
  console.log(response);  // 這里應(yīng)該打印的是45行返回的1,但是打印出來的確是aaaaaa
  return 2;  
}).then(function(response){
  console.log(response); // 這里應(yīng)該打印的是48行返回的2,但是打印出來的確是aaaaaa
})

setTimeout(function(){
   p.then(function(response){
     console.log("can i invoke?");
   })
},1000)


/**
 * 問題的根源在于什么呢?
 * 問題的根源是每次的then的返回值都是p,當(dāng)狀態(tài)是fulfilled,執(zhí)行的是onFulfilled(value)
 * 此處的value是p的value,也就是fulfilled狀態(tài)的value。根據(jù)規(guī)范,promise應(yīng)該是只能發(fā)射單值。
 * 而我們?cè)O(shè)計(jì)了一個(gè)callback堆棧中有一系列的值。生生的把promise變成了多值發(fā)射。
 * 
 * 所以,調(diào)整思路,每個(gè)then都應(yīng)該返回一個(gè)promise,這個(gè)promise應(yīng)該是一個(gè)全新的promise。
 * 具體實(shí)現(xiàn)見下一個(gè)例子。
 */
/**
 * 根據(jù)剛才的分析,我們重新優(yōu)化一下代碼
 * 1.去掉之前的多值設(shè)計(jì)
 * 2.每次的then 返回的都是一個(gè)全新的promise
 *
 */
function Promise(fn){
  var status = "pending"
  var value= null;
  var callbacks = [];
  var self = this;

  this.then = function(onFulfilled) {
    return new Promise(function(resolve){
      function handle(value){
        var res = typeof onFulfilled === "function" ? onFulfilled(value) : value;
        resolve(res);
      }
      // 如果是pending狀態(tài),則加入到注冊(cè)隊(duì)列中去。
      if(status === "pending"){
        callbacks.push(handle);
      // 如果是fulfilled 狀態(tài)。
      }else if(status === "fulfilled"){
          handle(value);
      }
    })
  }

  function resolve(newValue){
    value = newValue;
    status = "fulfilled";
    
    setTimeout(function(){
        callbacks.map(function(cb){
          cb(value);
        })
    },0)
  };

  fn(resolve);
}


// 
var p = new Promise(function(resolve){
    resolve("這是響應(yīng)的數(shù)據(jù)")
})

p.then(function(response){
  console.log(response);
  return 1;
}).then(function(response){
  console.log(response);
  return 2;  
}).then(function(response){
  console.log(response);
})

setTimeout(function(){
   p.then(function(response){
     console.log("can i invoke?");
   })
},1000)



/**
 * 運(yùn)行一下,完美輸出
 * 先是輸出“這是響應(yīng)的數(shù)據(jù)”,然后是“1”,然后是“2”, 然后是“can i invoke?”
 * 
 * 接下來我們要好好整理一下代碼了。把一些公用的方法放到構(gòu)造函數(shù)的原型上去。改造之后的例子見下一個(gè)例子
 */
/**
 * 根據(jù)剛才的分析,我們重新優(yōu)化一下代碼
 * 1.把私有屬性掛到實(shí)例上去
 * 2.把公共方法掛到構(gòu)造函數(shù)的原型上去
 *
 */
function Promise(fn){
  this.status = "pending";
  this.value= null;
  this.callbacks = [];
  var self = this;
  function resolve(newValue){
    self.value = newValue;
    self.status = "fulfilled";
    setTimeout(function(){
      self.callbacks.map(function(cb){
          cb(value);
        })
    },0)
  }
  fn(resolve);
}


Promise.prototype = Object.create(null);
Promise.prototype.constructor = Promise;


Promise.prototype.then = function(onFulfilled){
  var self = this;
  return new Promise(function(resolve){
    function handle(value){
      var res = typeof onFulfilled === "function"?  onFulfilled(value) : value;
      resolve(res);
    }
    if(self.status==="pending"){
      self.callbacks.push(handle);
    }else if(self.status ==="fulfilled"){
      handle(self.value);
    }
  })
}

// 使用
var p = new Promise(function(resolve){
    resolve("這是響應(yīng)的數(shù)據(jù)")
})

p.then(function(response){
  console.log(response);
  return 1;
}).then(function(response){
  console.log(response);
  return 2;  
}).then(function(response){
  console.log(response);
})

setTimeout(function(){
   p.then(function(response){
     console.log("can i invoke?");
   })
},1000)
5.處理注冊(cè)的函數(shù)返回值是promise的情況
/**
 * 不出意料,又要拋出問題了。當(dāng)then注冊(cè)的回調(diào)函數(shù)返回的是promise的時(shí)候,從這個(gè)then之后的所有then的注冊(cè)函數(shù)
 * 都應(yīng)該注冊(cè)在新返回的promise上。直到遇到下一個(gè)回調(diào)函數(shù)的返回值也是promise。
 * 
 * 實(shí)現(xiàn)思路:
 * 在handle中判斷注冊(cè)函數(shù)返回的是否是promise。如果是的話,則resolve這個(gè)返回的promise的值,具體代碼看一下36到38行
 * 
 */
function Promise(fn){
  this.status = "pending";
  this.value= null;
  this.callbacks = [];
  var self = this;
  function resolve(newValue){
    self.value = newValue;
    self.status = "fulfilled";
    setTimeout(function(){
      self.callbacks.map(function(cb){
          cb(value);
        })
    },0)
  }
  fn(resolve);
}


Promise.prototype = Object.create(null);
Promise.prototype.constructor = Promise;


Promise.prototype.then = function(onFulfilled){
  var self = this;
  var promise = new Promise(function(resolve){
    function handle(value){
      var res = typeof onFulfilled === "function"?  onFulfilled(value) : value;
      if(res instanceof Promise){
        promise = res;
        resolve(res.value);
      }else {
        resolve(res);
      }
    }
    if(self.status==="pending"){
      self.callbacks.push(handle);
    }else if(self.status ==="fulfilled"){
      handle(self.value);
    }
  })
  return promise;
}

// 使用
var p = new Promise(function(resolve){
    resolve("這是響應(yīng)的數(shù)據(jù)")
})

p.then(function(response){
  console.log(response);
  return new Promise(function(resolve){
    resolve("testtest")
  })
}).then(function(response){
  console.log(response);
  return 2;  
}).then(function(response){
  console.log(response);
})

setTimeout(function(){
   p.then(function(response){
     console.log("can i invoke?");
     return new Promise(function(resolve){
        resolve("hhhhhh")
      })
   }).then(function(response){
     console.log(response);
   })
},1000)

源碼全部在github上:https://github.com/JesseZhao1...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95209.html

相關(guān)文章

  • 啥?喝著闊落吃著西瓜就把Promise手寫出來了???

    摘要:嗝首先,我們通過字面可以看出來是一種解決方案,而且還有兩種傳統(tǒng)的解決方案回調(diào)函數(shù)和事件,,那么我們就來先聊聊這兩種方案。 前言 雖然今年已經(jīng)18年,但是今天還是要繼續(xù)聊聊ES6的東西,ES6已經(jīng)過去幾年,可是我們對(duì)于ES6的語法究竟是掌握了什么程度,是了解?會(huì)用?還是精通?相信大家和我一樣都對(duì)自己有著一個(gè)提升的心,對(duì)于新玩具可不能僅僅了解,對(duì)于其中的思想才是最吸引人的,所以接下來會(huì)通過...

    idisfkj 評(píng)論0 收藏0
  • 一步一步實(shí)現(xiàn)一個(gè)符合PromiseA+規(guī)范Promise庫(1)

    摘要:今天我們來自己手寫一個(gè)符合規(guī)范的庫。是異步編程的一種解決方案,比傳統(tǒng)的解決方案回調(diào)函數(shù)和事件更合理和更強(qiáng)大。我們可以看到,其實(shí)就是一個(gè)構(gòu)造函數(shù)。所以說我們的數(shù)組里存的是一個(gè)一個(gè)的的回調(diào)函數(shù),也就是一個(gè)一個(gè)。 今天我們來自己手寫一個(gè)符合PromiseA+規(guī)范的Promise庫。大家是不是很激動(dòng)呢?? showImg(https://segmentfault.com/img/bV6t4Z?...

    joyvw 評(píng)論0 收藏0
  • Promise源碼實(shí)現(xiàn)(完美符合Promise/A+規(guī)范)

    摘要:以上代碼,可以完美通過所有用例。在的函數(shù)中,為何需要這個(gè)同樣是因?yàn)橐?guī)范中明確表示因此我們需要這樣的來確保只會(huì)執(zhí)行一次。其他情況,直接返回以該值為成功狀態(tài)的對(duì)象。 Promise是前端面試中的高頻問題,我作為面試官的時(shí)候,問Promise的概率超過90%,據(jù)我所知,大多數(shù)公司,都會(huì)問一些關(guān)于Promise的問題。如果你能根據(jù)PromiseA+的規(guī)范,寫出符合規(guī)范的源碼,那么我想,對(duì)于面試...

    gaomysion 評(píng)論0 收藏0
  • Promise 詳解

    摘要:被觀察者管理內(nèi)部和的狀態(tài)轉(zhuǎn)變,同時(shí)通過構(gòu)造函數(shù)中傳遞的和方法以主動(dòng)觸發(fā)狀態(tài)轉(zhuǎn)變和通知觀察者。第一個(gè)回調(diào)函數(shù)是對(duì)象的狀態(tài)變?yōu)闀r(shí)調(diào)用,第二個(gè)回調(diào)函數(shù)是對(duì)象的狀態(tài)變?yōu)闀r(shí)調(diào)用可選實(shí)現(xiàn)主要實(shí)現(xiàn)第一步,初步構(gòu)建。 Promise 含義 Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案(回調(diào)函數(shù)和事件)更合合理、強(qiáng)大。所謂Promise,簡單來說就是一個(gè)容器,里面保存著某個(gè)未來才會(huì)結(jié)束的事件...

    anquan 評(píng)論0 收藏0
  • Promise 簡單實(shí)現(xiàn)

    摘要:簡單實(shí)現(xiàn)前言你可能知道,的任務(wù)執(zhí)行的模式有兩種同步和異步。你已經(jīng)實(shí)現(xiàn)了方法方法是一個(gè)很好用的方法。感興趣的朋友可以自行去研究哈附上代碼完整的實(shí)現(xiàn)個(gè)人博客鏈接 Promise 簡單實(shí)現(xiàn) 前言 你可能知道,javascript 的任務(wù)執(zhí)行的模式有兩種:同步和異步。 異步模式非常重要,在瀏覽器端,耗時(shí)很長的操作(例如 ajax 請(qǐng)求)都應(yīng)該異步執(zhí)行,避免瀏覽器失去響應(yīng)。 在異步模式編程中,我...

    dayday_up 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<