亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Promise 中的三兄弟 .all(), .race(), .allSettled()

vspiders / 1187人閱讀

摘要:對(duì)于的來(lái)說(shuō)基元函數(shù)包括組合函數(shù)的類型簽名返回情況完成如果傳入的可迭代對(duì)象為空,會(huì)同步地返回一個(gè)已完成狀態(tài)的。相反,如果是在指定的時(shí)間之后完成,剛返回結(jié)果就是一個(gè)拒絕狀態(tài)的從而觸發(fā)方法指定的回調(diào)函數(shù)。在行中,對(duì)每個(gè)小任務(wù)得到的結(jié)果進(jìn)行匯總。

為了保證的可讀性,本文采用意譯而非直譯。

想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你!

從ES6 開始,我們大都使用的是 Promise.all()Promise.race(),Promise.allSettled() 提案已經(jīng)到第4階段,因此將會(huì)成為ECMAScript 2020的一部分。

1.概述

Promise.all(promises: Iterable>): Promise>

Promise.all(iterable) 方法返回一個(gè) Promise 實(shí)例,此實(shí)例在 iterable 參數(shù)內(nèi)所有的 promise 都“完成(resolved)”或參數(shù)中不包含 promise 時(shí)回調(diào)完成(resolve);如果參數(shù)中 promise 有一個(gè)失敗(rejected),此實(shí)例回調(diào)失?。╮eject),失敗原因的是第一個(gè)失敗 promise 的結(jié)果

Promise.race(promises: Iterable>): Promise

Promise.race(iterable) 方法返回一個(gè) promise,一旦迭代器中的某個(gè)promise解決或拒絕,返回的 promise就會(huì)解決或拒絕。

Promise.allSettled(promises: Iterable>): Promise>>

Promise.allSettled()方法返回一個(gè)promise,該promise在所有給定的promise已被解析或被拒絕后解析,并且每個(gè)對(duì)象都描述每個(gè)promise的結(jié)果。

回顧: Promise 狀態(tài)

給定一個(gè)返回Promise的異步操作,以下這些是Promise的可能狀態(tài):

pending: 初始狀態(tài),既不是成功,也不是失敗狀態(tài)。

fulfilled: 意味著操作成功完成。

rejected: 意味著操作失敗。

Settled: Promise要么被完成,要么被拒絕。Promise一旦達(dá)成,它的狀態(tài)就不再改變。

3.什么是組合

又稱部分-整體模式,將對(duì)象整合成樹形結(jié)構(gòu)以表示“部分整體”的層次結(jié)構(gòu)。組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性,它基于兩種函數(shù):

基元函數(shù)(簡(jiǎn)短:基元)創(chuàng)建原子塊。

組合函數(shù)(簡(jiǎn)稱:組合)將原子和/或復(fù)合件組合在一起以形成復(fù)合件。

對(duì)于 JS 的 Promises 來(lái)說(shuō)

基元函數(shù)包括:Promise.resolve()、Promise.reject()

組合函數(shù):Promise.all(), Promise.race(), Promise.allSettled()

4. Promise.all()

Promise.all()的類型簽名:

Promise.all(promises: Iterable>): Promise>

返回情況:

完成(Fulfillment):
如果傳入的可迭代對(duì)象為空,Promise.all 會(huì)同步地返回一個(gè)已完成(resolved)狀態(tài)的promise。
如果所有傳入的 promise 都變?yōu)橥瓿蔂顟B(tài),或者傳入的可迭代對(duì)象內(nèi)沒(méi)有 promisePromise.all 返回的 promise 異步地變?yōu)橥瓿伞?br>在任何情況下,Promise.all 返回的 promise 的完成狀態(tài)的結(jié)果都是一個(gè)數(shù)組,它包含所有的傳入迭代參數(shù)對(duì)象的值(也包括非 promise 值)。

失敗/拒絕(Rejection):
如果傳入的 promise 中有一個(gè)失?。?b>rejected),Promise.all 異步地將失敗的那個(gè)結(jié)果給失敗狀態(tài)的回調(diào)函數(shù),而不管其它 promise 是否完成。

來(lái)個(gè)例子:

const promises = [
  Promise.resolve("a"),
  Promise.resolve("b"),
  Promise.resolve("c"),
];
Promise.all(promises)
  .then((arr) => assert.deepEqual(
    arr, ["a", "b", "c"]
  ));

如果其中的一個(gè) promise 被拒絕,那么又是什么情況:

const promises = [
  Promise.resolve("a"),
  Promise.resolve("b"),
  Promise.reject("ERROR"),
];
Promise.all(promises)
  .catch((err) => assert.equal(
    err, "ERROR"
  ));

下圖說(shuō)明Promise.all()是如何工作的

4.1 異步 .map() 與 Promise.all()

數(shù)組轉(zhuǎn)換方法,如.map()、.filter()等,用于同步計(jì)算。例如

function timesTwoSync(x) {
  return 2 * x;
}
const arr = [1, 2, 3];
const result = arr.map(timesTwoSync);
assert.deepEqual(result, [2, 4, 6]);

如果.map()的回調(diào)是基于Promise的函數(shù)會(huì)發(fā)生什么? 使用這種方式 .map()返回的的結(jié)果是一個(gè)Promises數(shù)組。

Promises數(shù)組不是普通代碼可以使用的數(shù)據(jù),但我們可以通過(guò)Promise.all()來(lái)解決這個(gè)問(wèn)題:它將Promises數(shù)組轉(zhuǎn)換為Promise,并使用一組普通值數(shù)組來(lái)實(shí)現(xiàn)。

function timesTwoAsync(x) {
  return new Promise(resolve => resolve(x * 2));
}
const arr = [1, 2, 3];
const promiseArr = arr.map(timesTwoAsync);
Promise.all(promiseArr)
  .then(result => {
    assert.deepEqual(result, [2, 4, 6]);
  });
更實(shí)際工作上關(guān)于 .map()示例

接下來(lái),咱們使用.map()Promise.all()Web下載文件。 首先,咱們需要以下幫助函數(shù):

function downloadText(url) {
  return fetch(url)
    .then((response) => { // (A)
      if (!response.ok) { // (B)
        throw new Error(response.statusText);
      }
      return response.text(); // (C)
    });
}

downloadText()使用基于Promise的fetch API 以字符串流的方式下載文件:

首先,它異步檢索響應(yīng)(第A行)。

response.ok(B行)檢查是否存在“找不到文件”等錯(cuò)誤。

如果沒(méi)有錯(cuò)誤,使用.text()(第C行)以字符串的形式取回文件的內(nèi)容。

在下面的示例中,咱們 下載了兩個(gè)文件

const urls = [
  "http://example.com/first.txt",
  "http://example.com/second.txt",
];

const promises = urls.map(
  url => downloadText(url));

Promise.all(promises)
  .then(
    (arr) => assert.deepEqual(
      arr, ["First!", "Second!"]
    ));

Promise.all()的一個(gè)簡(jiǎn)版實(shí)現(xiàn)
function all(iterable) {
  return new Promise((resolve, reject) => {
    let index = 0;
    for (const promise of iterable) {
      // Capture the current value of `index`
      const currentIndex = index;
      promise.then(
        (value) => {
          if (anErrorOccurred) return;
          result[currentIndex] = value;
          elementCount++;
          if (elementCount === result.length) {
            resolve(result);
          }
        },
        (err) => {
          if (anErrorOccurred) return;
          anErrorOccurred = true;
          reject(err);
        });
      index++;
    }
    if (index === 0) {
      resolve([]);
      return;
    }
    let elementCount = 0;
    let anErrorOccurred = false;
    const result = new Array(index);
  });
}
5. Promise.race()

Promise.race()方法的定義:

Promise.race(promises: Iterable>): Promise

Promise.race(iterable) 方法返回一個(gè) promise,一旦迭代器中的某個(gè)promise解決或拒絕,返回的 promise就會(huì)解決或拒絕。來(lái)幾個(gè)例子,瞧瞧:

const promises = [
  new Promise((resolve, reject) =>
    setTimeout(() => resolve("result"), 100)), // (A)
  new Promise((resolve, reject) =>
    setTimeout(() => reject("ERROR"), 200)), // (B)
];
Promise.race(promises)
  .then((result) => assert.equal( // (C)
    result, "result"));

在第 A 行,Promise 是完成狀態(tài) ,所以 第 C 行會(huì)執(zhí)行(盡管第 B 行被拒絕)。

如果 Promise 被拒絕首先執(zhí)行,在來(lái)看看情況是嘛樣的:

const promises = [
  new Promise((resolve, reject) =>
    setTimeout(() => resolve("result"), 200)),
  new Promise((resolve, reject) =>
    setTimeout(() => reject("ERROR"), 100)),
];
Promise.race(promises)
  .then(
    (result) => assert.fail(),
    (err) => assert.equal(
      err, "ERROR"));

注意,由于 Promse 先被拒絕,所以 Promise.race() 返回的是一個(gè)被拒絕的 Promise

這意味著Promise.race([])的結(jié)果永遠(yuǎn)不會(huì)完成。

下圖演示了Promise.race()的工作原理:

Promise.race() 在 Promise 超時(shí)下的情況

在本節(jié)中,我們將使用Promise.race()來(lái)處理超時(shí)的 Promise。 以下輔助函數(shù):

function resolveAfter(ms, value=undefined) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(value), ms);
  });
}

resolveAfter() 主要做的是在指定的時(shí)間內(nèi),返回一個(gè)狀態(tài)為 resolvePromise,值為為傳入的 value

調(diào)用上面方法:

function timeout(timeoutInMs, promise) {
  return Promise.race([
    promise,
    resolveAfter(timeoutInMs,
      Promise.reject(new Error("Operation timed out"))),
  ]);
}

timeout() 返回一個(gè)Promise,該 Promise 的狀態(tài)取決于傳入 promise 狀態(tài) 。

其中 timeout 函數(shù)中的 resolveAfter(timeoutInMs, Promise.reject(new Error("Operation timed out")) ,通過(guò) resolveAfter 定義可知,該結(jié)果返回的是一個(gè)被拒絕狀態(tài)的 Promise。

再來(lái)看看timeout(timeoutInMs, promise)的運(yùn)行情況。如果傳入promise在指定的時(shí)間之前狀態(tài)為完成時(shí),timeout 返回結(jié)果就是一個(gè)完成狀態(tài)的 Promise,可以通過(guò).then的第一個(gè)回調(diào)參數(shù)處理返回的結(jié)果。

timeout(200, resolveAfter(100, "Result!"))
  .then(result => assert.equal(result, "Result!"));

相反,如果是在指定的時(shí)間之后完成,剛 timeout 返回結(jié)果就是一個(gè)拒絕狀態(tài)的 Promise,從而觸發(fā)catch方法指定的回調(diào)函數(shù)。

timeout(100, resolveAfter(2000, "Result!"))
  .catch(err => assert.deepEqual(err, new Error("Operation timed out")));

重要的是要了解“Promise 超時(shí)”的真正含義:

如果傳入入Promise 較到的得到解決,其結(jié)果就會(huì)給返回的 Promise

如果沒(méi)有足夠快得到解決,輸出的 Promise 的狀態(tài)為拒絕。

也就是說(shuō),超時(shí)只會(huì)阻止傳入的Promise,影響輸出 Promise(因?yàn)镻romise只能解決一次), 但它并沒(méi)有阻止傳入Promise的異步操作。

5.2 Promise.race() 的一個(gè)簡(jiǎn)版實(shí)現(xiàn)

以下是 Promise.race()的一個(gè)簡(jiǎn)化實(shí)現(xiàn)(它不執(zhí)行安全檢查)

function race(iterable) {
  return new Promise((resolve, reject) => {
    for (const promise of iterable) {
      promise.then(
        (value) => {
          if (settlementOccurred) return;
          settlementOccurred = true;
          resolve(value);
        },
        (err) => {
          if (settlementOccurred) return;
          settlementOccurred = true;
          reject(err);
        });
    }
    let settlementOccurred = false;
  });
}
6.Promise.allSettled()

“Promise.allSettled”這一特性是由Jason Williams,Robert PamelyMathias Bynens提出。

promise.allsettle()方法的定義:

Promise.allSettled(promises: Iterable<Promise>)
: Promise<Array>>

它返回一個(gè)ArrayPromise,其元素具有以下類型特征:

type SettlementObject = FulfillmentObject | RejectionObject;

interface FulfillmentObject {
  status: "fulfilled";
  value: T;
}

interface RejectionObject {
  status: "rejected";
  reason: unknown;
}

Promise.allSettled()方法返回一個(gè)promise,該promise在所有給定的promise已被解析或被拒絕后解析,并且每個(gè)對(duì)象都描述每個(gè)promise的結(jié)果。

舉例說(shuō)明, 比如各位用戶在頁(yè)面上面同時(shí)填了3個(gè)獨(dú)立的表單, 這三個(gè)表單分三個(gè)接口提交到后端, 三個(gè)接口獨(dú)立, 沒(méi)有順序依賴, 這個(gè)時(shí)候我們需要等到請(qǐng)求全部完成后給與用戶提示表單提交的情況

在多個(gè)promise同時(shí)進(jìn)行時(shí)咱們很快會(huì)想到使用Promise.all來(lái)進(jìn)行包裝, 但是由于Promise.all的短路特性, 三個(gè)提交中若前面任意一個(gè)提交失敗, 則后面的表單也不會(huì)進(jìn)行提交了, 這就與咱們需求不符合.

Promise.allSettledPromise.all類似, 其參數(shù)接受一個(gè)Promise的數(shù)組, 返回一個(gè)新的Promise, 唯一的不同在于, 其不會(huì)進(jìn)行短路, 也就是說(shuō)當(dāng)Promise全部處理完成后我們可以拿到每個(gè)Promise的狀態(tài), 而不管其是否處理成功.

下圖說(shuō)明promise.allsettle()是如何工作的

6.1 Promise.allSettled() 例子

這是Promise.allSettled() 使用方式快速演示示例

Promise.allSettled([
  Promise.resolve("a"),
  Promise.reject("b"),
])
.then(arr => assert.deepEqual(arr, [
  { status: "fulfilled", value:  "a" },
  { status: "rejected",  reason: "b" },
]));
6.2 Promise.allSettled() 較復(fù)雜點(diǎn)的例子

這個(gè)示例類似于.map()Promise.all()示例(我們從其中借用了downloadText()函數(shù)):我們下載多個(gè)文本文件,這些文件的url存儲(chǔ)在一個(gè)數(shù)組中。但是,這一次,咱們不希望在出現(xiàn)錯(cuò)誤時(shí)停止,而是希望繼續(xù)執(zhí)行。Promise.allSettled()允許咱們這樣做:

const urls = [
  "http://example.com/exists.txt",
  "http://example.com/missing.txt",
];

const result = Promise.allSettled(
  urls.map(u => downloadText(u)));
result.then(
  arr => assert.deepEqual(
    arr,
    [
      {
        status: "fulfilled",
        value: "Hello!",
      },
      {
        status: "rejected",
        reason: new Error("Not Found"),
      },
    ]
));
6.3 Promise.allSettled() 的簡(jiǎn)化實(shí)現(xiàn)

這是promise.allsettle()的簡(jiǎn)化實(shí)現(xiàn)(不執(zhí)行安全檢查)

function allSettled(iterable) {
  return new Promise((resolve, reject) => {
    function addElementToResult(i, elem) {
      result[i] = elem;
      elementCount++;
      if (elementCount === result.length) {
        resolve(result);
      }
    }

    let index = 0;
    for (const promise of iterable) {
      // Capture the current value of `index`
      const currentIndex = index;
      promise.then(
        (value) => addElementToResult(
          currentIndex, {
            status: "fulfilled",
            value
          }),
        (reason) => addElementToResult(
          currentIndex, {
            status: "rejected",
            reason
          }));
      index++;
    }
    if (index === 0) {
      resolve([]);
      return;
    }
    let elementCount = 0;
    const result = new Array(index);
  });
}
7. 短路特性

Promise.all()romise.race() 都具有 短路特性

Promise.all(): 如果參數(shù)中 promise 有一個(gè)失?。╮ejected),此實(shí)例回調(diào)失?。╮eject)

Promise.race():如果參數(shù)中某個(gè)promise解決或拒絕,返回的 promise就會(huì)解決或拒絕。

8.并發(fā)性和 Promise.all() 8.1 順序執(zhí)行與并發(fā)執(zhí)行

考慮下面的代碼:

asyncFunc1()
  .then(result1 => {
    assert.equal(result1, "one");
    return asyncFunc2();
  })
  .then(result2 => {
    assert.equal(result2, "two");
  });

使用.then()順序執(zhí)行基于Promise的函數(shù):只有在 asyncFunc1()的結(jié)果被解決后才會(huì)執(zhí)行asyncFunc2() 。

Promise.all() 是并發(fā)執(zhí)行的

Promise.all([asyncFunc1(), asyncFunc2()])
  .then(arr => {
    assert.deepEqual(arr, ["one", "two"]);
  });
9.2 并發(fā)技巧:關(guān)注操作何時(shí)開始

確定并發(fā)異步代碼的技巧:關(guān)注異步操作何時(shí)啟動(dòng),而不是如何處理它們的Promises。

例如,下面的每個(gè)函數(shù)都同時(shí)執(zhí)行asyncFunc1()asyncFunc2(),因?yàn)樗鼈儙缀跬瑫r(shí)啟動(dòng)。

function concurrentAll() {
  return Promise.all([asyncFunc1(), asyncFunc2()]);
}

function concurrentThen() {
  const p1 = asyncFunc1();
  const p2 = asyncFunc2();
  return p1.then(r1 => p2.then(r2 => [r1, r2]));
}

另一方面,以下兩個(gè)函數(shù)依次執(zhí)行asyncFunc1()asyncFunc2(): asyncFunc2()僅在asyncFunc1()的解決之后才調(diào)用。

function sequentialThen() {
  return asyncFunc1()
    .then(r1 => asyncFunc2()
      .then(r2 => [r1, r2]));
}

function sequentialAll() {
  const p1 = asyncFunc1();
  const p2 = p1.then(() => asyncFunc2());
  return Promise.all([p1, p2]);
}

9.3 Promise.all() 與 Fork-Join 分治編程

Promise.all() 與并發(fā)模式“fork join”松散相關(guān)。重溫一下咱們前面的一個(gè)例子:

Promise.all([
    // (A) fork
    downloadText("http://example.com/first.txt"),
    downloadText("http://example.com/second.txt"),
  ])
  // (B) join
  .then(
    (arr) => assert.deepEqual(
      arr, ["First!", "Second!"]
    ));

Fork:在A行中,分割兩個(gè)異步任務(wù)并同時(shí)執(zhí)行它們。

Join:在B行中,對(duì)每個(gè)小任務(wù)得到的結(jié)果進(jìn)行匯總。

代碼部署后可能存在的BUG沒(méi)法實(shí)時(shí)知道,事后為了解決這些BUG,花了大量的時(shí)間進(jìn)行l(wèi)og 調(diào)試,這邊順便給大家推薦一個(gè)好用的BUG監(jiān)控工具 Fundebug。

交流

干貨系列文章匯總?cè)缦?,覺(jué)得不錯(cuò)點(diǎn)個(gè)Star,歡迎 加群 互相學(xué)習(xí)。

https://github.com/qq44924588...

我是小智,公眾號(hào)「大遷世界」作者,對(duì)前端技術(shù)保持學(xué)習(xí)愛(ài)好者。我會(huì)經(jīng)常分享自己所學(xué)所看的干貨,在進(jìn)階的路上,共勉!

關(guān)注公眾號(hào),后臺(tái)回復(fù)福利,即可看到福利,你懂的。

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

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

相關(guān)文章

  • 深度理解Promise--Promise的特點(diǎn)和方法詳解

    摘要:實(shí)例生成以后,用方法分別指定狀態(tài)和狀態(tài)的回調(diào)函數(shù)。則是或的別名,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。上述代碼也可以理解成這樣處理和前一個(gè)回調(diào)函數(shù)運(yùn)行時(shí)發(fā)生的錯(cuò)誤發(fā)生錯(cuò)誤方法用于指定不管對(duì)象最后狀態(tài)如何,都會(huì)執(zhí)行的回調(diào)函數(shù)。 什么是promise? Promise(承諾),在程序中的意思就是承諾我過(guò)一段時(shí)間(通常是一個(gè)異步操作)后會(huì)給你一個(gè)結(jié)果,是異步編程的一種解決方案。從語(yǔ)法上說(shuō),原生Pro...

    wqj97 評(píng)論0 收藏0
  • 精讀《What's new in javascript》

    摘要:舉例來(lái)說(shuō)即便某個(gè)失敗了,也不會(huì)導(dǎo)致的發(fā)生,這樣在不在乎是否有項(xiàng)目失敗,只要拿到都結(jié)束的信號(hào)的場(chǎng)景很有用。對(duì)于則稍有不同只要有子項(xiàng),就會(huì)完成,哪怕第一個(gè)了,而第二個(gè)了,也會(huì),而對(duì)于,這種場(chǎng)景會(huì)直接。 1. 引言 本周精讀的內(nèi)容是:Google I/O 19。 2019 年 Google I/O 介紹了一些激動(dòng)人心的 JS 新特性,這些特性有些已經(jīng)被主流瀏覽器實(shí)現(xiàn),并支持 polyfill...

    dabai 評(píng)論0 收藏0
  • JS引擎:它們是如何工作的?從調(diào)用堆棧到Promise,需要知道的所有內(nèi)容

    摘要:最受歡迎的引擎是,由和使用,用于,以及使用的。引擎它們是如何工作的全局執(zhí)行上下文和調(diào)用堆棧剛剛了解了引擎如何讀取變量和函數(shù)聲明,它們最終被放入了全局內(nèi)存堆中。事件循環(huán)只有一個(gè)任務(wù)它檢查調(diào)用堆棧是否為空。 為了保證可讀性,本文采用意譯而非直譯。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! 有沒(méi)有想過(guò)瀏覽器如何讀取和運(yùn)行JS代碼? 這看起來(lái)很神奇,我們可以通過(guò)瀏覽...

    lavnFan 評(píng)論0 收藏0
  • JavaScript引擎是如何工作的?從調(diào)用棧到Promise你需要知道的一切

    摘要:最受歡迎的引擎是,在和中使用,用于,以及所使用的。怎么處理每個(gè)引擎都有一個(gè)基本組件,稱為調(diào)用棧。也就是說(shuō),如果有其他函數(shù)等待執(zhí)行,函數(shù)是不能離開調(diào)用棧的。每個(gè)異步函數(shù)在被送入調(diào)用棧之前必須通過(guò)回調(diào)隊(duì)列。例如方法是在中傳遞的回調(diào)函數(shù)。 ? 翻譯:瘋狂的技術(shù)宅 原文:www.valentinog.com/blog/engine… 從Call Stack,Global Me...

    zzbo 評(píng)論0 收藏0
  • JavaScript引擎是如何工作的?從調(diào)用棧到Promise你需要知道的一切

    摘要:最受歡迎的引擎是,在和中使用,用于,以及所使用的。單線程的我們說(shuō)是單線程的,因?yàn)橛幸粋€(gè)調(diào)用棧處理我們的函數(shù)。也就是說(shuō),如果有其他函數(shù)等待執(zhí)行,函數(shù)是不能離開調(diào)用棧的。每個(gè)異步函數(shù)在被送入調(diào)用棧之前必須通過(guò)回調(diào)隊(duì)列。 翻譯:瘋狂的技術(shù)宅原文:https://www.valentinog.com/bl... 本文首發(fā)微信公眾號(hào):前端先鋒歡迎關(guān)注,每天都給你推送新鮮的前端技術(shù)文章 sh...

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

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

0條評(píng)論

閱讀需要支付1元查看
<