国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Promise總結(jié)

馬龍駒 / 937人閱讀

摘要:一旦狀態(tài)被改變,就不會(huì)再變,任何時(shí)候都能得到這個(gè)結(jié)果,與事件回調(diào)不同,事件回調(diào)在事件過去后無法再調(diào)用函數(shù)。如果不設(shè)置回調(diào)函數(shù),內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部處于時(shí),無法感知的狀態(tài)剛剛開始還是即將完成。以為調(diào)用函數(shù),為,和為參數(shù)調(diào)用返回。

更好的閱度體驗(yàn)

前言

API

Promise特點(diǎn)

狀態(tài)跟隨

V8中的async await和Promise

實(shí)現(xiàn)一個(gè)Promise

參考

前言

作為一個(gè)前端開發(fā),使用了Promise一年多了,一直以來都停留在API的調(diào)用階段,沒有很好的去深入。剛好最近閱讀了V8團(tuán)隊(duì)的一篇如何實(shí)現(xiàn)更快的async await,借著這個(gè)機(jī)會(huì)整理了Promise的相關(guān)理解。文中如有錯(cuò)誤,請輕噴~

API

Promise是社區(qū)中對于異步的一種解決方案,相對于回調(diào)函數(shù)和事件機(jī)制更直觀和容易理解。ES6 將其寫進(jìn)了語言標(biāo)準(zhǔn),統(tǒng)一了用法,提供了原生的Promise對象。

這里只對API的一些特點(diǎn)做記錄,如果需要詳細(xì)教程,推薦阮老師的Promise對象一文

new Promise
--創(chuàng)建一個(gè)promise實(shí)例

Promise.prototype.then(resolve, reject)
--then方法返回一個(gè)新的Promise實(shí)例

Promise.prototype.catch(error)
--.then(null, rejection)或.then(undefined, rejection)的別名,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。
--錯(cuò)誤會(huì)一直傳遞,直到被catch,如果沒有catch,則沒有任何反應(yīng)
--catch返回一個(gè)新的Promise實(shí)例

Promise.prototype.finally()
--指定不管 Promise 對象最后狀態(tài)如何,都會(huì)執(zhí)行的操作。
--實(shí)現(xiàn)如下:

Promise.prototype.finally = function (callback) {
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};

Promise.all([promise Array])
--將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例
--所有子promise執(zhí)行完成后,才執(zhí)行all的resolve,參數(shù)為所有子promise返回的數(shù)組
--某個(gè)子promise出錯(cuò)時(shí),執(zhí)行all的reject,參數(shù)為第一個(gè)被reject的實(shí)例的返回值
--某個(gè)子promise自己catch時(shí),不會(huì)傳遞reject給all,因?yàn)閏atch重新返回一個(gè)promise實(shí)例

Promise.race([promise Array])
--將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例。
--子promise有一個(gè)實(shí)例率先改變狀態(tài),race的狀態(tài)就跟著改變。那個(gè)率先改變的 Promise 實(shí)例的返回值,就傳遞給race的回調(diào)函數(shù)。

Promise.resolve()
--將現(xiàn)有對象轉(zhuǎn)為 Promise 對象
--參數(shù)是promise實(shí)例, 原封不動(dòng)的返回
--參數(shù)是一個(gè)thenable對象 將這個(gè)對象轉(zhuǎn)為 Promise 對象,狀態(tài)為resolved
--參數(shù)是一個(gè)原始值 返回一個(gè)新的 Promise 對象,狀態(tài)為resolved
--不帶有任何參數(shù) 返回一個(gè)resolved狀態(tài)的 Promise 對象。
--等價(jià)于如下代碼

Promise.resolve("foo")
// 等價(jià)于
new Promise(resolve => resolve("foo"))

Promise.reject()
--返回一個(gè)新的 Promise 實(shí)例,該實(shí)例的狀態(tài)為rejected
--Promise.reject()方法的參數(shù),會(huì)原封不動(dòng)地作為reject的理由,變成后續(xù)方法的參數(shù)。

Promise特點(diǎn)
很多文章都是把resolve當(dāng)成fulfilled,本文也是,但本文還有另外一個(gè)resolved,指的是該P(yáng)romise已經(jīng)被處理,注意兩者的區(qū)別  

1. 對象具有三個(gè)狀態(tài),分別是pending(進(jìn)行中)、fulfilled(resolve)(已成功)、reject(已失敗),并且對象的狀態(tài)不受外界改變,只能從pending到fulfilled或者pending到reject。  

2. 一旦狀態(tài)被改變,就不會(huì)再變,任何時(shí)候都能得到這個(gè)結(jié)果,與事件回調(diào)不同,事件回調(diào)在事件過去后無法再調(diào)用函數(shù)。  

3. 一個(gè)promise一旦resolved,再次resolve/reject將失效。即只能resolved一次。  

4. 值穿透,傳給then或者catch的參數(shù)為非函數(shù)時(shí),會(huì)發(fā)生穿透(下面有示例代碼)  

5. 無法取消,Promise一旦運(yùn)行,無法取消。  

6. 如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部  

7. 處于pending時(shí),無法感知promise的狀態(tài)(剛剛開始還是即將完成)。
值穿透代碼:
new Promise(resolve=>resolve(8))
  .then()
  .then()
  .then(function foo(value) {
    console.log(value)  // 8
  })
狀態(tài)追隨

狀態(tài)追隨的概念和下面的v8處理asyac await相關(guān)聯(lián)

狀態(tài)跟隨就是指將一個(gè)promise(代指A)當(dāng)成另外一個(gè)promise(代指B)的resolve參數(shù),即B的狀態(tài)會(huì)追隨A。
如下代碼所示:

const promiseA = new Promise((resolve) => {
  setTimeout(() => {
    resolve("ccc")
  }, 3000)
})
const promiseB = new Promise(res => {
  res(promiseA)
})
promiseB.then((arg) => {
  console.log(arg) // print "ccc" after 3000ms
})

按理說,promiseB應(yīng)該是已經(jīng)處于resolve的狀態(tài), 但是依然要3000ms后才打印出我們想要的值, 這難免讓人困惑

在ES的標(biāo)準(zhǔn)文檔中有這么一句話可以幫助我們理解:

A resolved promise may be pending, fulfilled or rejected.

就是說一個(gè)已經(jīng)處理的promise,他的狀態(tài)有可能是pending, fulfilled 或者 rejected。 這與我們前面學(xué)的不一樣啊, resolved了的promise不應(yīng)該是處于結(jié)果狀態(tài)嗎?這確實(shí)有點(diǎn)反直覺,結(jié)合上面的例子看,當(dāng)處于狀態(tài)跟隨時(shí),即使promiseB立即被resolved了,但是因?yàn)樗冯S了promiseA的狀態(tài),而A的狀態(tài)則是pending,所以才說處于resolved的promiseB的狀態(tài)是pending。

再看另外一個(gè)例子:

const promiseA = new Promise((resolve) => {
  setTimeout(() => {
    resolve("ccc")
  }, 3000)
})
const promiseB = new Promise(res => {
  setTimeout(() => {
    res(promiseA)
  }, 5000)
})
promiseB.then((arg) => {
  console.log(arg) // print "ccc" after 5000ms
})

其實(shí)理解了上面的話,這一段的代碼也比較容易理解,只是因?yàn)樽约褐斑M(jìn)了牛角尖,所以特意記錄下來:

3s后 promiseA狀態(tài)變成resolve

5s后 promiseB被resolved, 追隨promiseA的狀態(tài)

因?yàn)閜romiseA的狀態(tài)為resolve, 所以打印 ccc

V8中的async await和Promise

在進(jìn)入正題之前,我們可以先看下面這段代碼:

const p = Promise.resolve();

(async () => {
  await p;
  console.log("after:await");
})();

p.then(() => {
  console.log("tick:a");
}).then(() => {
  console.log("tick:b");
});

V8團(tuán)隊(duì)的博客中, 說到這段代碼的運(yùn)行結(jié)果有兩種:

Node8(錯(cuò)誤的):

after: await  
tick a  
tick b  

Node10(正確的):

tick a  
tick b  
after await  

ok, 問題來了, 為啥是這個(gè)樣子?
先從V8對于await的處理說起, 這里引用一張官方博客的圖來說明Node8 await的偽代碼:

Node10 await

對于上面的例子代碼翻譯過來就(該代碼引用自V8是怎么實(shí)現(xiàn)更快的async await)是:

const p = Promise.resolve();

(() => {
  const implicit_promise = new Promise(resolve => {
    const promise = new Promise(res => res(p));
    promise.then(() => {
      console.log("after:await");
      resolve();
    });
  });

  return implicit_promise;
})();

p.then(() => {
  console.log("tick:a");
}).then(() => {
  console.log("tick:b");
});

很明顯,內(nèi)部那一句 new Promise(res => res(p)); 代碼就是一個(gè)狀態(tài)跟隨,即promise追隨p的狀態(tài),那這跟上面的結(jié)果又有什么關(guān)系?

在繼續(xù)深入之前, 我們還需要了解一些概念:

task和microtask
JavaScript 中有 task 和 microtask 的概念。 Task 處理 I/O 和計(jì)時(shí)器等事件,一次執(zhí)行一個(gè)。 Microtask 為 async/await 和 promise 實(shí)現(xiàn)延遲執(zhí)行,并在每個(gè)任務(wù)結(jié)束時(shí)執(zhí)行。 總是等到 microtasks 隊(duì)列被清空,事件循環(huán)執(zhí)行才會(huì)返回。

如官方提供的一張圖:

EnqueueJob、PromiseResolveThenableJob和PromiseReactionJob

EnquequeJob: 存放兩種類型的任務(wù), 即PromiseResolveThenableJob和PromiseReactionJob, 并且都是屬于microtask類型的任務(wù)

PromiseReactionJob: 可以通俗的理解為promise中的回調(diào)函數(shù)

PromiseResolveThenableJob(promiseToResolve, thenable, then): 創(chuàng)建和 promiseToResolve 關(guān)聯(lián)的 resolve function 和 reject function。以 then 為調(diào)用函數(shù),thenable 為this,resolve function和reject function 為參數(shù)調(diào)用返回。(下面利用代碼講解)

狀態(tài)跟隨的內(nèi)部

再以之前的代碼為例子

const promiseA = new Promise((resolve) => {
  resolve("ccc")
})
const promiseB = new Promise(res => {
  res(promiseA)
})

當(dāng)promiseB被resolved的時(shí)候, 也就是將一個(gè)promise(代指A)當(dāng)成另外一個(gè)promise(代指B)的resolve參數(shù),會(huì)向EnquequeJob插入一個(gè)PromiseResolveThenableJob任務(wù),PromiseResolveThenableJob大概做了如下的事情:

() => { 
  promiseA.then(
    resolvePromiseB, 
    rejectPromiseB
  );
}

并且當(dāng)resolvePromiseB執(zhí)行后, promiseB的狀態(tài)才變成resolve,也就是B追隨A的狀態(tài)

Node10中的流程
1. p處于resolve狀態(tài),promise調(diào)用then被resolved,同時(shí)向microtask插入任務(wù)PromiseResolveThenableJob  
2. p.then被調(diào)用, 向microtask插入任務(wù)tickA  
3. 執(zhí)行PromiseResolveThenableJob, 向microtask插入任務(wù)resolvePromise(如上面的promiseA.then(...))  
4. 執(zhí)行tickA(即輸出tick: a),返回一個(gè)promise, 向microtask插入任務(wù)tickB  
5. 因?yàn)閙icrotask的任務(wù)還沒執(zhí)行完, 繼續(xù)  
6. 執(zhí)行resolvePromise, 此時(shí)promise終于變成resolve, 向microtask插入任務(wù)"after await"  
7. 執(zhí)行tickB(即輸出tick: b)  
8. 執(zhí)行"after await"(即輸出"after await")
更快的await

老規(guī)矩, 先補(bǔ)一張偽代碼圖:

翻譯過來就是醬紫:

const p = Promise.resolve();

(() => {
  const implicit_promise = new Promise(resolve => {
    const promise = Promise.resolve(p)
    promise.then(() => {
      console.log("after:await");
      resolve();
    });
  });

  return implicit_promise;
})();

p.then(() => {
  console.log("tick:a");
}).then(() => {
  console.log("tick:b");
});

因?yàn)閜是一個(gè)promise, 然后Promise.resolve會(huì)直接將P返回,也就是

p === promise // true

因?yàn)橹苯臃祷亓藀,所以省去了中間兩個(gè)microtask任務(wù),并且輸出的順序也變得正常,也就是V8所說的更快的async await

實(shí)現(xiàn)一個(gè)Promise

先實(shí)現(xiàn)一個(gè)基礎(chǔ)的函數(shù)

function Promise(cb) {
  const that = this
  that.value = undefined // Promise的值
  that.status = "pending" // Promise的狀態(tài)
  that.resolveArray = [] // resolve函數(shù)集合
  that.rejectArray = []  // reject函數(shù)集合

  function resolve(value) {
    if (value instanceof Promise) {
      return value.then(resolve, reject)
    }
    setTimeout(function() {
      if (that.status === "pending") { // 處于pending狀態(tài) 循環(huán)調(diào)用
        that.value = value
        that.status = "resolve"
        for(let i = 0; i < that.resolveArray.length; i++) {
          that.resolveArray[i](value)
        }
      }
    })
  }
  function reject(reason) {
    if (reason instanceof Promise) {
      return reason.then(resolve, reject)
    }
    setTimeout(function() {
      if (that.status === "pending") { // 處于pending狀態(tài) 循環(huán)調(diào)用
        that.value = reason
        that.status = "reject"
        for(let i = 0; i < that.rejectArray.length; i++) {
          that.rejectArray[i](reason)
        }
      }
    })
  }

  try {
    cb(resolve, reject)
  } catch (e) {
    reject(e)
  }
}
Promise.prototype.then = function(onResolve, onReject) {
  var that = this
  var promise2 // 返回的Promise

  onResolve = typeof onResolve === "function" ? onResolve : function(v) { return v }  //如果不是函數(shù) 則處理穿透值
  onReject = typeof onReject === "function" ? onReject : function(v) { return v } //如果不是函數(shù) 則處理穿透值

  if (that.status === "resolve") {
    return promise2 = new Promise(function(resolve, reject) {
      setTimeout(function() {
        try {
          const x = onResolve(that.value)
          if (x instanceof Promise) { // 如果onResolved的返回值是一個(gè)Promise對象,直接取它的結(jié)果做為promise2的結(jié)果
            x.then(resolve, reject)
          } else {
            resolve(x)
          }
        } catch (e) {
          reject(e)
        }
      })
    })
  }

  if (that.status === "reject") {
    return promise2 = new Promise(function(resolve, reject) {
      setTimeout(function() {
        try {
          const x = onResolve(that.value)
          if (x instanceof Promise) { // 如果onResolved的返回值是一個(gè)Promise對象,直接取它的結(jié)果做為promise2的結(jié)果
            x.then(resolve, reject)
          } else {
            reject(x)
          }
        } catch (e) {
          reject(e)
        }
      })
    })
  }

  if (that.status === "pending") {
    return promise2 = new Promise(function(resolve, reject) {
      that.resolveArray.push(function(value) {
        try {
          var x = onResolve(value)
          if (x instanceof Promise) {
            x.then(resolve, reject)
          }
        } catch (e) {
          reject(e)
        }
      })
      that.rejectArray.push(function(reason) {
        try {
          var x = onReject(reason)
          if (x instanceof Promise) {
            x.then(resolve, reject)
          }
        } catch (e) {
          reject(e)
        }
      })
    })
  }
}
Promise.prototype.catch = function(onReject) {
  return this.then(null, onReject)
}
參考

v8是怎么實(shí)現(xiàn)更快的 await ?深入理解 await 的運(yùn)行機(jī)制
V8中更快的異步函數(shù)和promise
剖析Promise內(nèi)部結(jié)構(gòu),一步一步實(shí)現(xiàn)一個(gè)完整的、能通過所有Test case的Promise類
PromiseA+
ES6入門
深入Promise

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/108920.html

相關(guān)文章

  • Promise的幾個(gè)擴(kuò)展API總結(jié)

    摘要:的幾個(gè)擴(kuò)展總結(jié)描述和相反,當(dāng)所有的被拒絕之后,方法執(zhí)行完成的決議,如果存在一個(gè)執(zhí)行完成的決議,方法則執(zhí)行拒絕里邊的所有實(shí)例反過來就好了執(zhí)行到此執(zhí)行到此描述忽略被拒絕的,只需要有一個(gè)完成的,方法就執(zhí)行完成操作,如果全部的都被拒絕,方法執(zhí)行拒絕 Promise的幾個(gè)擴(kuò)展API總結(jié) 1. Promise.none 描述: 和 Promise.all 相反,當(dāng)所有的promise被拒絕之后,n...

    李義 評論0 收藏0
  • promise以及async、await學(xué)習(xí)總結(jié)

    Promise/async、await幫我們解決了什么 它給我們提供了一種新的異步編程解決方案,同時(shí)避免了困擾已久的回調(diào)地獄 // 異步的處理可能會(huì)產(chǎn)生這樣的回調(diào)地獄(第二個(gè)異步操作和第一個(gè)異步的結(jié)果有關(guān)系) let Ajax = function(data, success, error){ $.ajax({ data: data, success: function...

    zero 評論0 收藏0
  • promise以及async、await學(xué)習(xí)總結(jié)

    Promise/async、await幫我們解決了什么 它給我們提供了一種新的異步編程解決方案,同時(shí)避免了困擾已久的回調(diào)地獄 // 異步的處理可能會(huì)產(chǎn)生這樣的回調(diào)地獄(第二個(gè)異步操作和第一個(gè)異步的結(jié)果有關(guān)系) let Ajax = function(data, success, error){ $.ajax({ data: data, success: function...

    mist14 評論0 收藏0
  • promise以及async、await學(xué)習(xí)總結(jié)

    Promise/async、await幫我們解決了什么 它給我們提供了一種新的異步編程解決方案,同時(shí)避免了困擾已久的回調(diào)地獄 // 異步的處理可能會(huì)產(chǎn)生這樣的回調(diào)地獄(第二個(gè)異步操作和第一個(gè)異步的結(jié)果有關(guān)系) let Ajax = function(data, success, error){ $.ajax({ data: data, success: function...

    fuchenxuan 評論0 收藏0
  • 簡要總結(jié)microtask和macrotask

    摘要:眾所周知和都屬于上述異步任務(wù)的一種那到底為什么和會(huì)有順序之分這就是我想分析總結(jié)的問題所在了和的作用是為了讓瀏覽器能夠從內(nèi)部獲取的內(nèi)容并確保執(zhí)行棧能夠順序進(jìn)行。只要執(zhí)行棧沒有其他在執(zhí)行,在每個(gè)結(jié)束時(shí),隊(duì)列就會(huì)在回調(diào)后處理。 前言 我是在做前端面試題中看到了setTimeout和Promise的比較,然后第一次看到了microtask和macrotask的概念,在閱讀了一些文章之后發(fā)現(xiàn)沒有...

    yexiaobai 評論0 收藏0

發(fā)表評論

0條評論

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