中文在线免费看视频_国产成人精品亚洲日本在线观看_亚洲精品第一综合99久久_国产亚洲精品日韩综合网

當前位置: 首頁 / 技術干貨 / 正文
手封MyPromise

2022-12-02

   mypromise

  引子

  面試時如果被問到“如果沒有Promise,能不能自己實現(xiàn)一個”,就是在深度考察對異步的理解了;

  如果你的回答是“能,我封過”,則必然令人刮目相看~

  事實上,作為ES6新增的API,即使沒有,用戶也完全可以基于想要的效果自己去實現(xiàn)一個;

  這里給到大家我個人的實現(xiàn):MyPromise;

  源碼地址

  實現(xiàn)思路

  將then/catch/finally中入?yún)⒌幕卣{(diào)函數(shù)按順序收集到一個隊列中;

  親自實現(xiàn)一下resolve和reject方法;

  一旦實例resolve就將隊列頭部的catch回調(diào)都彈出,一旦實例reject就將隊列頭部的then回調(diào)都彈出,然后拿取隊列頭部的回調(diào)函數(shù)實行起來;

  每次回調(diào)的執(zhí)行結(jié)果即返回值需要繼續(xù)resolve或reject一下,然后繼續(xù)遞歸執(zhí)行上述過程,直到回調(diào)隊列為空;

  接收任務執(zhí)行器

  當我們new出一個MyPromise,并內(nèi)置一個任務執(zhí)行器函數(shù)的時候,需要在MyPromise的構(gòu)造器中接收任務執(zhí)行器函數(shù),并同步地、立即地將其執(zhí)行起來;

  要特別注意:任務執(zhí)行器函數(shù)是同步地跑在主線程的,而不屬于異步回調(diào);

  test.js

  new MyPromise(

  /* 任務執(zhí)行器:2秒后隨機履約或毀約 */

  (resolve, reject) => {

  setTimeout(() => {

  Math.random() > 0.5 ? resolve("data0") : reject(new Error("一張好人卡"));

  }, 2000);

  }

  )

  MyPromise.js

  class MyPromise {

  constructor(executor) {

  /* 接收任務執(zhí)行器并立即調(diào)用(同步調(diào)用) */

  this.executor = executor;

  this.executor();

  }

  }

  定義resolve與reject

  任務執(zhí)行器函數(shù)會在稍后履約(resolve)或毀約(reject)

  因此要告訴MyPromise履約或毀約時具體做什么

  這里我們先做一下簡單的打印

  MyPromise.js

  class MyPromise {

  constructor(executor) {

  /* 接收任務執(zhí)行器并立即調(diào)用(同步調(diào)用) */

  /* 綁定執(zhí)行器函數(shù)中的resolve與reject */

  this.executor = executor.bind(

  this, //當前promise實例

  

  //當前promise實例執(zhí)行resolve時,this不變

  MyPromise.doResolve.bind(this),

  

  //當前promise實例執(zhí)行reject時,this不變

  MyPromise.doReject.bind(this)

  );

  this.executor();

  }

  

  /* promise實例執(zhí)行resolve */

  static doResolve(data) {

  console.log("doResolve", data);

  }

  

  /* promise實例執(zhí)行reject */

  static doReject(err) {

  console.log("doReject", err);

  }

  }

  

  module.exports = MyPromise;

  明確回調(diào)期望

  明確一下異步任務履約/毀約后我們希望做什么

  我們希望一旦異步任務resolve就執(zhí)行then中的回調(diào)

  我們希望一旦異步任務reject就執(zhí)行catch中的回調(diào)

  我們希望異步任務無論成功還是失敗,最終都執(zhí)行finally中的回調(diào)

  期望如下:test.js

  const MyPromise = require("./MyPromiseX")

  

  new MyPromise(

  /* 任務執(zhí)行器:2秒后隨機履約或毀約 */

  (resolve, reject) => {

  setTimeout(() => {

  Math.random() > 0.1 ? resolve("data0") : reject(new Error("一張好人卡"));

  }, 2000);

  }

  )

  .then(

  data => {

  console.log("then1:data=",data)

  return "data from then1"

  // throw new Error("err from then1")

  }

  )

  .catch(

  err => {

  console.log("catch1:err=",err)

  return "data from catch1"

  }

  )

  .finally(

  ()=>console.log("finally:game over!")

  )

  收集回調(diào)隊列

  每一個then中有一個成功回調(diào)

  每一個catch中有一個失敗回調(diào)

  finally中有一個最終回調(diào)

  我們先按順序?qū)⑦@些回調(diào)收集在一個隊列中

  代碼如下:MyPromise.js

  class MyPromise {

  constructor(executor) {

  

  // 回調(diào)隊列

  this.callbacks = [];

  

  /* 接收任務執(zhí)行器并立即調(diào)用(同步調(diào)用) */

  // 綁定執(zhí)行器函數(shù)中的resolve與reject

  this.executor = executor.bind(

  this, //當前promise實例

  

  //當前promise實例執(zhí)行resolve時,this不變

  MyPromise.doResolve.bind(this),

  

  //當前promise實例執(zhí)行reject時,this不變

  MyPromise.doReject.bind(this)

  );

  

  // 立即調(diào)用任務執(zhí)行器

  this.executor();

  }

  

  /* promise實例執(zhí)行resolve */

  static doResolve(data) {

  console.log("doResolve", data);

  }

  

  /* promise實例執(zhí)行reject */

  static doReject(err) {

  console.log("doReject", err);

  }

  

  /* 收集成功回調(diào)到隊列 */

  then(onData) {

  // 將來一旦Promise毀約 回調(diào)隊列頭部的所有then回調(diào)都要彈出作廢

  this.callbacks.push({ type: "then", callback: onData });

  return this;

  }

  

  /* 收集失敗回調(diào)到隊列 */

  catch(onErr) {

  // 將來一旦Promise履約 回調(diào)隊列頭部的所有catch回調(diào)都要彈出作廢

  this.callbacks.push({ type: "catch", callback: onErr });

  return this;

  }

  

  /* 收集終點回調(diào)到隊列(此處假設只有一個終點回調(diào)) */

  finally(onFinish) {

  this.callbacks.push({ type: "finally", callback: onFinish });

  return this;

  }

  }

  

  module.exports = MyPromise;

  此時在測試腳本test.js的末尾打印一下回調(diào)隊列的話,你會看到如下輸出:

  [

  { type: 'then', callback: [Function (anonymous)] },

  { type: 'catch', callback: [Function (anonymous)] },

  { type: 'finally', callback: [Function (anonymous)] }

  ]

  如果來上一堆亂序的then/catch/finally的話,則你會看到如下輸出:

  [

  { type: 'then', callback: [Function (anonymous)] },

  { type: 'then', callback: [Function (anonymous)] },

  { type: 'then', callback: [Function (anonymous)] },

  { type: 'then', callback: [Function (anonymous)] },

  { type: 'catch', callback: [Function (anonymous)] },

  { type: 'catch', callback: [Function (anonymous)] },

  { type: 'then', callback: [Function (anonymous)] },

  { type: 'finally', callback: [Function (anonymous)] }

  ]

  連環(huán)作案(履約或毀約)

  讓我們在每次成功或失敗后,都隨機地繼續(xù)履約或毀約起來!

  test.js

  const MyPromise = require("./MyPromiseX")

  

  const p = new MyPromise(

  /* 任務執(zhí)行器:2秒后隨機履約或毀約 */

  (resolve, reject) => {

  setTimeout(() => {

  Math.random() > 0.5 ? resolve("data0") : reject(new Error("一張好人卡"));

  }, 2000);

  }

  )

  .then(

  data => {

  console.log("then1:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  return "data from then1"

  // throw new Error("err from then1")

  }

  )

  .then(

  data => {

  console.log("then2:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  return MyPromise.resolve("data from then2")

  // return MyPromise.reject("err from then2")

  }

  )

  .then(

  data => {

  console.log("then3:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  return new MyPromise(

  (resolve,reject) => setTimeout(() => {

  resolve("data from then3")

  // reject("err from then3")

  }, 2000)

  )

  }

  )

  .then(

  /* 這里本質(zhì)繼續(xù)履約了一個undefined */

  data => console.log("then4:data=",data)

  )

  .catch(

  err => {

  console.log("catch1:err=",err)

  

  /* 繼續(xù)履約 */

  return "data from catch1"

  }

  )

  .catch(

  /* 這里本質(zhì)繼續(xù)履約了一個undefined */

  err => console.log("catch2:err=",err)

  )

  .then(

  /* 這里本質(zhì)繼續(xù)履約了一個undefined */

  data => console.log("then5:data=",data)

  )

  .finally(

  /* 這里本質(zhì)繼續(xù)履約了一個undefined */

  ()=>console.log("finally:game over!")

  )

  

  // 打印一下MyPromise對象的回調(diào)隊列

  console.log("p.callbacks",p.callbacks);

  所謂MyPromise.resolve(data)或MyPromise.reject(err)無非也就是newPromise(executor)的一個語法糖而已,實現(xiàn)如下:

  MyPromise.js片段

  /* 語法糖:創(chuàng)建一個立即resolve的Promise對象 */

  static resolve(data) {

  return new MyPromise((resolve) => resolve(data));

  }

  

  /* 語法糖:創(chuàng)建一個立即reject的Promise對象 */

  static reject(err) {

  return new MyPromise((resolve, reject) => reject(err));

  }

  準備執(zhí)行連環(huán)回調(diào)

  我們無非想要如下效果:

  只要前面的環(huán)節(jié)履約了:在回調(diào)隊列中找出下一個type為then的回調(diào)執(zhí)行起來;

  只要前面的環(huán)節(jié)毀約了:在回調(diào)隊列中找出下一個type為catch的回調(diào)執(zhí)行起來;

  找下一個then回調(diào)前,所有位于它前面的catch都驅(qū)逐先;

  找下一個catch回調(diào)前,所有位于它前面的then都驅(qū)逐先;

  我們來擼碼實現(xiàn)之!

  定義MyPromise狀態(tài)

  class MyPromise {

  /* Promise狀態(tài)定義 */

  static STATUS_PENDING = 0; // 掛起態(tài)

  static STATUS_FULFILLED = 1; // 履約態(tài)

  static STATUS_REJECTED = 2; // 毀約態(tài)

  ...

  }

  定義回調(diào)入?yún)?/p>

  constructor(executor) {

  /* 回調(diào)隊列 + 回調(diào)入?yún)?(JS單線程模型=每次只能有一個回調(diào)被執(zhí)行) */

  this.callbacks = [];

  

  // 定義給回調(diào)傳的入?yún)ⅲ瑹o論是數(shù)據(jù)還是錯誤,我們統(tǒng)稱為cbArg

  this.cbArg = null;

  ...

  }

  定義驅(qū)逐器

  成功時:從回調(diào)隊列頭部把所有的catch驅(qū)逐

  失敗時:從回調(diào)隊列頭部把所有的then驅(qū)逐

  /*

  成功時:從回調(diào)隊列頭部把所有的catch驅(qū)逐

  失敗時:從回調(diào)隊列頭部把所有的then驅(qū)逐

  */

  shiftCallbacksWithType(type) {

  /* 只要回調(diào)隊列中還有回調(diào),就把隊列頭部type為指定類型的回調(diào)彈出去 */

  while (this.callbacks.length && this.callbacks[0].type === type) {

  // 驅(qū)逐一個回調(diào)函數(shù)

  this.callbacks.shift();

  }

  }

  執(zhí)行連環(huán)回調(diào)

  當前任履約時

  狀態(tài)設置為履約態(tài)

  將回調(diào)入?yún)⒃O置為需要履約的數(shù)據(jù)

  找下一個then里的回調(diào)執(zhí)行起來

  /* promise實例執(zhí)行resolve */

  static doResolve(data) {

  /* 設置狀態(tài)為履約態(tài) + 設置回調(diào)時的入?yún)?+ 拉起下一次回調(diào) */

  this.status = MyPromise.STATUS_FULFILLED;

  

  // 回調(diào)入?yún)閿?shù)據(jù)

  this.cbArg = data;

  

  // 拉起下一次then回調(diào)

  setTimeout(() => {

  this.next();

  });

  }

  當前任毀約時

  狀態(tài)設置為毀約態(tài)

  將回調(diào)入?yún)⒃O置為毀約的原因

  找下一個catch里的回調(diào)執(zhí)行起來

  /* promise實例執(zhí)行reject */

  static doReject(err) {

  /* 設置狀態(tài)為毀約態(tài) + 設置回調(diào)時的錯誤 + 拉起下一次回調(diào) */

  this.status = MyPromise.STATUS_REJECTED;

  

  // 回調(diào)入?yún)殄e誤

  this.cbArg = err;

  

  // 拉起下一次catch回調(diào)

  setTimeout(() => {

  this.next();

  });

  }

  執(zhí)行下一次回調(diào)

  整個MyPromise最核心的邏輯來了

  只要當前MyPromise為履約態(tài),就驅(qū)逐隊列頭部所有的catch回調(diào)先

  只要當前MyPromise為毀約態(tài),就驅(qū)逐隊列頭部所有的then回調(diào)先

  拿取隊列頭部的那個回調(diào)執(zhí)行起來

  next() {

  /* 確定該回調(diào)哪一個callback */

  if (this.status === MyPromise.STATUS_FULFILLED) {

  // 履約時:彈光隊列頭部的catch回調(diào)

  this.shiftCallbacksWithType("catch");

  }

  

  if (this.status === MyPromise.STATUS_REJECTED) {

  // 毀約時:彈光隊列頭部的then回調(diào)

  this.shiftCallbacksWithType("then");

  }

  

  /* 如果回調(diào)隊列已空,則直接結(jié)束程序 */

  if (!this.callbacks.length) {

  console.log("回調(diào)隊列已空");

  return;

  }

  

  /* 拉取回調(diào)隊列頭部的回調(diào)函數(shù)(注意這里無視了type只解構(gòu)出函數(shù)本身) */

  let { callback } = this.callbacks.shift();

  // 執(zhí)行回調(diào)并拿到其結(jié)果(value或promise對象)

  let value = callback(this.cbArg);

  }

  當回調(diào)返回value

  test.js片段

  .then(

  data => {

  console.log("then1:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  return "data from then1"

  // throw new Error("err from then1")

  }

  )

  當回調(diào)返回一個新的(非MyPromise對象)的普通value時,我們繼續(xù)向后resolve它

  程序會繼續(xù)doResolve,doResolve內(nèi)部會繼續(xù)拉起下一次next

  下一次next找出的回調(diào)還有新的返回值

  遞歸了解一下!歸了解一下!了解一下!解一下!一下!下!

  next() {

  ...

  // 執(zhí)行回調(diào)并拿到其結(jié)果(value或promise對象)

  let value = callback(this.cbArg);

  

  /* 如果回調(diào)函數(shù)返回一個value 繼續(xù)向下resolve(value) */

  if (!(value instanceof MyPromise)) {

  MyPromise.doResolve.call(this, value);

  }

  ...

  }

  當回調(diào)拋出錯誤時

  test.js片段

  .then(

  data => {

  console.log("then1:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  // return "data from then1"

  throw new Error("err from then1")

  }

  )

  try-catch起來,把錯誤信息reject一下

  程序會繼續(xù)doReject,doReject內(nèi)部會繼續(xù)拉起下一次next

  下一次next找出的回調(diào)還有新的返回值

  遞歸了解一下!歸了解一下!了解一下!解一下!一下!下!

  next() {

  ...

  /* 拉取回調(diào)隊列頭部的回調(diào)函數(shù)(注意這里無視了type只解構(gòu)出函數(shù)本身) */

  let { callback } = this.callbacks.shift();

  

  /* 防止回調(diào)函數(shù)中throw錯誤 */

  try {

  // 執(zhí)行回調(diào)并拿到其結(jié)果(value或promise對象)

  let value = callback(this.cbArg);

  

  /* 如果回調(diào)函數(shù)返回一個value 繼續(xù)向下resolve(value) */

  if (!(value instanceof MyPromise)) {

  MyPromise.doResolve.call(this, value);

  }else {

  ...

  }

  } catch (err) {

  // 回調(diào)函數(shù)拋出錯誤時相當于reject(err)

  MyPromise.doReject.call(this, err);

  }

  }

  當回調(diào)返回一個新的MP對象時

  .then(

  data => {

  console.log("then2:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  return MyPromise.resolve("data from then2")

  // return MyPromise.reject("err from then2")

  }

  )

  .then(

  data => {

  console.log("then3:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  return new MyPromise(

  (resolve,reject) => setTimeout(() => {

  resolve("data from then3")

  // reject("err from then3")

  }, 2000)

  )

  }

  )

  首先,MP的構(gòu)造器一定會被調(diào)用!

  構(gòu)造器里有this.executor(),this.executor()里有resolve(data)或reject(err),也就是doResolve(data)或doReject(err)

  不斷遞歸next()找下一次回調(diào)的過程會自發(fā)地跑起

  這個該死的MP對象可能自帶一個回調(diào)隊列

  我們把當前MP對象剩余的回調(diào)隊列過戶給它即可

  next() {

  ...

  /* 拉取回調(diào)隊列頭部的回調(diào)函數(shù)(注意這里無視了type只解構(gòu)出函數(shù)本身) */

  let { callback } = this.callbacks.shift();

  

  /* 防止回調(diào)函數(shù)中throw錯誤 */

  try {

  // 執(zhí)行回調(diào)并拿到其結(jié)果(value或promise對象)

  let value = callback(this.cbArg);

  

  /* 如果回調(diào)函數(shù)返回一個value 繼續(xù)向下resolve(value) */

  if (!(value instanceof MyPromise)) {

  ...

  }

  else {

  // 如果回調(diào)函數(shù)返回一個Promise對象

  // 將后續(xù)所有callback過戶給新的Promise對象

  value.callbacks = value.callbacks.concat(this.callbacks);

  }

  } catch (err) {...}

  }

  完整的next函數(shù)

  遞歸inside!

  /*

  從回調(diào)隊列里拉取下一個適當?shù)腸allback并回調(diào)之

  這是MyPromise的核心代碼:遞歸inside!

  */

  next() {

  /* 確定該回調(diào)哪一個callback */

  if (this.status === MyPromise.STATUS_FULFILLED) {

  // 履約時:彈光隊列頭部的catch回調(diào)

  this.shiftCallbacksWithType("catch");

  }

  

  if (this.status === MyPromise.STATUS_REJECTED) {

  // 毀約時:彈光隊列頭部的then回調(diào)

  this.shiftCallbacksWithType("then");

  }

  

  /* 如果回調(diào)隊列已空,則直接結(jié)束程序 */

  if (!this.callbacks.length) {

  console.log("回調(diào)隊列已空");

  return;

  }

  

  /* 拉取回調(diào)隊列頭部的回調(diào)函數(shù)(注意這里無視了type只解構(gòu)出函數(shù)本身) */

  let { callback } = this.callbacks.shift();

  

  /* 防止回調(diào)函數(shù)中throw錯誤 */

  try {

  // 執(zhí)行回調(diào)并拿到其結(jié)果(value或promise對象)

  let value = callback(this.cbArg);

  

  /* 如果回調(diào)函數(shù)返回一個value 繼續(xù)向下resolve(value) */

  if (!(value instanceof MyPromise)) {

  MyPromise.doResolve.call(this, value);

  }

  else {

  // 如果回調(diào)函數(shù)返回一個Promise對象

  // 將后續(xù)所有callback過戶給新的Promise對象

  value.callbacks = value.callbacks.concat(this.callbacks);

  }

  } catch (err) {

  // 回調(diào)函數(shù)拋出錯誤時相當于reject(err)

  MyPromise.doReject.call(this, err);

  }

  }

  完整代碼

  MyPromise.js

  class MyPromise {

  /* Promise狀態(tài)定義 */

  static STATUS_PENDING = 0; // 掛起態(tài)

  static STATUS_FULFILLED = 1; // 履約態(tài)

  static STATUS_REJECTED = 2; // 毀約態(tài)

  

  constructor(executor) {

  /* 回調(diào)隊列 + 回調(diào)入?yún)?(JS單線程模型=每次只能有一個回調(diào)被執(zhí)行) */

  this.callbacks = [];

  

  // 定義給回調(diào)傳的入?yún)?,無論是數(shù)據(jù)還是錯誤,我們統(tǒng)稱為cbArg

  this.cbArg = null;

  

  /* 綁定執(zhí)行器函數(shù)中的resolve與reject */

  this.executor = executor.bind(

  this, //當前promise實例

  

  //當前promise實例執(zhí)行resolve時,this不變

  MyPromise.doResolve.bind(this),

  

  //當前promise實例執(zhí)行reject時,this不變

  MyPromise.doReject.bind(this)

  );

  

  // 執(zhí)行任務前先將Promise狀態(tài)設置為pending

  this.status = MyPromise.STATUS_PENDING;

  

  // 執(zhí)行任務(任務中會resolve/doResolve或reject/doReject)

  this.executor();

  }

  

  /* promise實例執(zhí)行resolve */

  static doResolve(data) {

  /* 設置狀態(tài)為履約態(tài) + 設置回調(diào)時的入?yún)?+ 拉起下一次回調(diào) */

  this.status = MyPromise.STATUS_FULFILLED;

  

  // 回調(diào)入?yún)閿?shù)據(jù)

  this.cbArg = data;

  

  // 拉起下一次then回調(diào)

  setTimeout(() => {

  this.next();

  });

  }

  

  /* promise實例執(zhí)行reject */

  static doReject(err) {

  /* 設置狀態(tài)為毀約態(tài) + 設置回調(diào)時的錯誤 + 拉起下一次回調(diào) */

  this.status = MyPromise.STATUS_REJECTED;

  

  // 回調(diào)入?yún)殄e誤

  this.cbArg = err;

  

  // 拉起下一次catch回調(diào)

  setTimeout(() => {

  this.next();

  });

  }

  

  /*

  成功時:從回調(diào)隊列頭部把所有的catch驅(qū)逐

  失敗時:從回調(diào)隊列頭部把所有的then驅(qū)逐

  */

  shiftCallbacksWithType(type) {

  /* 只要回調(diào)隊列中還有回調(diào),就把隊列頭部type為指定類型的回調(diào)彈出去 */

  while (this.callbacks.length && this.callbacks[0].type === type) {

  // 驅(qū)逐一個回調(diào)函數(shù)

  this.callbacks.shift();

  }

  }

  

  /*

  從回調(diào)隊列里拉取下一個適當?shù)腸allback并回調(diào)之

  這是MyPromise的核心代碼:遞歸inside!

  */

  next() {

  /* 確定該回調(diào)哪一個callback */

  if (this.status === MyPromise.STATUS_FULFILLED) {

  // 履約時:彈光隊列頭部的catch回調(diào)

  this.shiftCallbacksWithType("catch");

  }

  

  if (this.status === MyPromise.STATUS_REJECTED) {

  // 毀約時:彈光隊列頭部的then回調(diào)

  this.shiftCallbacksWithType("then");

  }

  

  /* 如果回調(diào)隊列已空,則直接結(jié)束程序 */

  if (!this.callbacks.length) {

  console.log("回調(diào)隊列已空");

  return;

  }

  

  /* 拉取回調(diào)隊列頭部的回調(diào)函數(shù)(注意這里無視了type只解構(gòu)出函數(shù)本身) */

  let { callback } = this.callbacks.shift();

  

  /* 防止回調(diào)函數(shù)中throw錯誤 */

  try {

  // 執(zhí)行回調(diào)并拿到其結(jié)果(value或promise對象)

  let value = callback(this.cbArg);

  

  /* 如果回調(diào)函數(shù)返回一個value 繼續(xù)向下resolve(value) */

  if (!(value instanceof MyPromise)) {

  MyPromise.doResolve.call(this, value);

  }

  else {

  // 如果回調(diào)函數(shù)返回一個Promise對象

  // 將后續(xù)所有callback過戶給新的Promise對象

  value.callbacks = value.callbacks.concat(this.callbacks);

  }

  } catch (err) {

  // 回調(diào)函數(shù)拋出錯誤時相當于reject(err)

  MyPromise.doReject.call(this, err);

  }

  }

  

  /* 語法糖:創(chuàng)建一個立即resolve的Promise對象 */

  static resolve(data) {

  return new MyPromise((resolve) => resolve(data));

  }

  

  /* 語法糖:創(chuàng)建一個立即reject的Promise對象 */

  static reject(err) {

  return new MyPromise((resolve, reject) => reject(err));

  }

  

  /* 收集成功回調(diào)到隊列 */

  then(onData) {

  // 將來一旦Promise毀約 回調(diào)隊列頭部的所有then回調(diào)都要彈出作廢

  this.callbacks.push({ type: "then", callback: onData });

  return this;

  }

  

  /* 收集失敗回調(diào)到隊列 */

  catch(onErr) {

  // 將來一旦Promise履約 回調(diào)隊列頭部的所有catch回調(diào)都要彈出作廢

  this.callbacks.push({ type: "catch", callback: onErr });

  return this;

  }

  

  /* 收集終點回調(diào)到隊列(此處假設只有一個終點回調(diào)) */

  finally(onFinish) {

  this.callbacks.push({ type: "finally", callback: onFinish });

  return this;

  }

  }

  

  module.exports = MyPromise;

  測試代碼test.js

  const MyPromise = require("./MyPromise3")

  

  const p = new MyPromise(

  /* 任務執(zhí)行器:2秒后隨機履約或毀約 */

  (resolve, reject) => {

  setTimeout(() => {

  Math.random() > 0.1 ? resolve("data0") : reject(new Error("一張好人卡"));

  }, 2000);

  }

  )

  .then(

  data => {

  console.log("then1:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  return "data from then1"

  // throw new Error("err from then1")

  }

  )

  .then(

  data => {

  console.log("then2:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  return MyPromise.resolve("data from then2")

  // return MyPromise.reject("err from then2")

  }

  )

  .then(

  data => {

  console.log("then3:data=",data)

  

  /* 繼續(xù)履約或毀約! */

  return new MyPromise(

  (resolve,reject) => setTimeout(() => {

  resolve("data from then3")

  // reject("err from then3")

  }, 2000)

  )

  }

  )

  .then(

  /* 這里本質(zhì)繼續(xù)履約了一個undefined */

  data => console.log("then4:data=",data)

  )

  .catch(

  err => {

  console.log("catch1:err=",err)

  

  /* 繼續(xù)履約 */

  return "data from catch1"

  }

  )

  .catch(

  /* 這里本質(zhì)繼續(xù)履約了一個undefined */

  err => console.log("catch2:err=",err)

  )

  .then(

  /* 這里本質(zhì)繼續(xù)履約了一個undefined */

  data => console.log("then5:data=",data)

  )

  .finally(

  /* 這里本質(zhì)繼續(xù)履約了一個undefined */

  ()=>console.log("finally:game over!")

  )

  

  // 打印一下MyPromise對象的回調(diào)隊列

  console.log("p.callbacks",p.callbacks);

  測試效果

  https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5c47910678fd41acba1eed2ea02bbabb~tplv-k3u1fbpfcp-watermark.image?

好程序員公眾號

  • · 剖析行業(yè)發(fā)展趨勢
  • · 匯聚企業(yè)項目源碼

好程序員開班動態(tài)

More+
  • HTML5大前端 <高端班>

    開班時間:2021-04-12(深圳)

    開班盛況

    開班時間:2021-05-17(北京)

    開班盛況
  • 大數(shù)據(jù)+人工智能 <高端班>

    開班時間:2021-03-22(杭州)

    開班盛況

    開班時間:2021-04-26(北京)

    開班盛況
  • JavaEE分布式開發(fā) <高端班>

    開班時間:2021-05-10(北京)

    開班盛況

    開班時間:2021-02-22(北京)

    開班盛況
  • Python人工智能+數(shù)據(jù)分析 <高端班>

    開班時間:2021-07-12(北京)

    預約報名

    開班時間:2020-09-21(上海)

    開班盛況
  • 云計算開發(fā) <高端班>

    開班時間:2021-07-12(北京)

    預約報名

    開班時間:2019-07-22(北京)

    開班盛況
IT培訓IT培訓
在線咨詢
IT培訓IT培訓
試聽
IT培訓IT培訓
入學教程
IT培訓IT培訓
立即報名
IT培訓

Copyright 2011-2023 北京千鋒互聯(lián)科技有限公司 .All Right 京ICP備12003911號-5 京公網(wǎng)安備 11010802035720號

中文在线免费看视频_国产成人精品亚洲日本在线观看_亚洲精品第一综合99久久_国产亚洲精品日韩综合网

            亚洲福利国产精品| 国产精品久久久久一区| 自拍视频在线观看一区二区| 日本一不卡视频| 色综合久久精品| 国产日本亚洲高清| 麻豆国产欧美日韩综合精品二区 | ...xxx性欧美| 久久99最新地址| 欧美日韩国产首页| 亚洲黄色录像片| 丁香亚洲综合激情啪啪综合| 欧美成人一区二区三区在线观看| 一区二区三区四区不卡视频| 成人综合日日夜夜| 久久免费看少妇高潮| 青青草国产精品97视觉盛宴| 色婷婷综合久久久中文一区二区| 国产精品婷婷午夜在线观看| 精品在线一区二区三区| 67194成人在线观看| 亚洲自拍与偷拍| 一本色道久久综合狠狠躁的推荐| 国产精品美女久久久久高潮| 韩国一区二区在线观看| 欧美一区二区精品在线| 视频在线观看一区| 欧美色国产精品| 亚洲夂夂婷婷色拍ww47| 色综合天天综合色综合av| 中文字幕一区av| 99在线热播精品免费| 久久久久久影视| 国产精品资源在线看| 久久蜜桃一区二区| 国产麻豆午夜三级精品| 久久久精品综合| 国产成人在线视频网站| 国产亚洲制服色| 国产精品伊人色| 国产人成一区二区三区影院| 国产黄色成人av| 欧美国产综合一区二区| 成人免费观看av| 亚洲欧美在线视频| 一本大道av一区二区在线播放| 亚洲久草在线视频| 色婷婷亚洲精品| 亚洲高清中文字幕| 欧美久久一区二区| 蜜臀av一区二区在线观看| 日韩免费观看高清完整版 | 亚洲国产婷婷综合在线精品| 欧美在线短视频| 日韩精品久久久久久| 日韩一二三四区| 国产麻豆9l精品三级站| 国产精品日韩成人| 91精品福利在线| 丝袜脚交一区二区| 亚洲精品在线一区二区| 国产成人自拍网| 亚洲欧美一区二区久久| 欧美视频中文字幕| 日本va欧美va精品| 久久精品一区二区三区不卡| av一区二区三区四区| 一片黄亚洲嫩模| 欧美一区二区免费观在线| 黑人巨大精品欧美一区| 国产精品视频看| 欧美色爱综合网| 激情偷乱视频一区二区三区| 国产精品视频第一区| 在线观看日韩av先锋影音电影院| 日本不卡视频在线| 国产欧美日韩另类视频免费观看| 91啪亚洲精品| 视频一区二区不卡| 国产日韩av一区二区| 在线观看国产日韩| 激情综合色丁香一区二区| 国产精品毛片a∨一区二区三区 | 国产**成人网毛片九色 | 日本不卡的三区四区五区| 久久久久久久久久美女| 91污片在线观看| 麻豆高清免费国产一区| 亚洲欧美影音先锋| 日韩美女视频在线| 91丨porny丨最新| 日本伊人色综合网| 国产精品久久久久9999吃药| 欧美精品三级日韩久久| 国产v综合v亚洲欧| 天堂影院一区二区| 国产精品免费免费| 日韩亚洲欧美高清| 91久久精品一区二区三| 国产老女人精品毛片久久| 亚洲高清免费在线| 国产精品免费丝袜| 精品美女一区二区| 精品视频在线看| 成人综合婷婷国产精品久久免费| 亚洲6080在线| 中文字幕欧美一区| 日韩欧美中文一区| 色欧美日韩亚洲| 国产suv一区二区三区88区| 五月天激情综合网| 亚洲视频网在线直播| 久久看人人爽人人| 制服丝袜亚洲网站| 欧美中文字幕一二三区视频| 国产不卡在线一区| 久久精品国产精品亚洲红杏| 亚洲精品免费播放| 国产欧美日韩一区二区三区在线观看| 欧美日韩精品三区| 色综合久久88色综合天天免费| 国产一区在线看| 免费成人小视频| 亚洲成人免费视| 伊人色综合久久天天| 中文字幕乱码一区二区免费| 欧美大尺度电影在线| 在线不卡欧美精品一区二区三区| 色视频欧美一区二区三区| 成人精品视频.| 国产精品一区二区在线观看网站| 免费观看91视频大全| 五月婷婷综合激情| 亚洲一区二区三区激情| 亚洲男人天堂av| 亚洲欧洲精品成人久久奇米网| 国产欧美一区二区精品婷婷| 精品久久久久久亚洲综合网| 欧美一级二级三级蜜桃| 制服.丝袜.亚洲.另类.中文| 欧美三级电影精品| 欧美午夜电影网| 欧美三区在线观看| 91福利精品第一导航| 日本精品一区二区三区四区的功能| av电影天堂一区二区在线观看| 成人午夜精品一区二区三区| 国产成人综合自拍| 国产成人av电影在线| 高清成人在线观看| 成人av动漫网站| 99在线精品一区二区三区| caoporm超碰国产精品| av不卡在线播放| 色综合中文字幕国产| 色婷婷一区二区三区四区| 色婷婷激情综合| 在线精品观看国产| 欧美日韩午夜在线视频| 欧美日韩国产美女| 欧美一区二区三区色| 日韩欧美一区二区视频| www久久精品| 国产精品嫩草99a| 亚洲欧美色综合| 亚洲成人动漫在线免费观看| 日韩高清在线电影| 精品一区二区成人精品| 国产一区二区福利视频| 国产mv日韩mv欧美| 94色蜜桃网一区二区三区| 91传媒视频在线播放| 欧美精品xxxxbbbb| 精品日韩在线一区| 欧美激情艳妇裸体舞| 亚洲丝袜另类动漫二区| 亚洲国产成人精品视频| 免费看黄色91| 高清shemale亚洲人妖| 97超碰欧美中文字幕| 欧美日韩国产综合一区二区| 日韩欧美美女一区二区三区| 国产日韩高清在线| 亚洲自拍欧美精品| 免费欧美在线视频| 成人网页在线观看| 欧美吻胸吃奶大尺度电影| 日韩三级.com| 国产精品人妖ts系列视频| 亚洲一区二区精品视频| 久久精品国产精品亚洲综合| 高清不卡一二三区| 欧美日韩国产一级二级| 2021久久国产精品不只是精品| 亚洲欧洲性图库| 青青草国产精品97视觉盛宴| 丁香天五香天堂综合| 欧美无乱码久久久免费午夜一区| 欧美变态tickle挠乳网站| 1024成人网色www|