Promise 究竟是什麼玩意?

本文主要討論一下Promise概念以及一些使用場景和如何正確使用。本文討論的內容大概是適合對Promise的初學者,若是你已經對Promise很熟悉了,那麼沒有必要看。面試

Promisie究竟是什麼玩意?

這兩天參加了一個線上作題面試,有一道Promise的題目,頗有意思。作題的過程當中讓我對Promise又有了新的理解。markdown

Promise是什麼?

Prosmise這東西本質上就是一個設計的對象,根本沒有什麼神祕的。Promise就像一個飛去來器,扔出去,會有兩種結果:
(1)成功的飛回手上
(2)飛的時候忽然爆炸了,渣都沒了,只聽到一聲響:「reject!」
如今咱們直接看一個代碼:async

// boomerang 是一個Promise 函數,你不用關心它如何實現的
// 你能夠假設它是一個平時你能用到的HTTP call 能夠返回特定的內容
// 它回成功返回數據(resolve),也可能失敗(reject)
const boomerang = (s = 0, type = 'resolve', data = `飛去來器${s}型號回來了`) => {
  if (type !== 'resolve') {
    return new Promise((resolve, reject) =>
      setTimeout(() => {
        reject(new Error(`${s}毫秒後爆炸`));
      }, s)
    );
  }
  return new Promise((resolve) =>
    setTimeout(() => {
      resolve(data);
    }, s)
  );
};

const world = () => {
  console.log('吃大蔥');
  const a = boomerang(0);
  console.log(a);
  const b = boomerang(1000, 'reject').catch((e) => {
    return e.toString();
  });
  console.log(b);
  const c = boomerang(2000);
  console.log(c);
  console.log('吃大蒜');
};

world();
複製代碼

那麼這段代碼返回什麼呢?如Prosmise不是特別熟悉,你可能會想錯了。你可能會誤覺得會返回’吃大蔥‘’ 吃大蒜‘而後後面跟着其它值是undefinied;其實不是,下面看一下返回值:函數

吃大蔥
Promise { <pending> }
Promise { <pending> }
Promise { <pending> }
吃大蒜
複製代碼

Promise不是不會當即執行的嗎?怎麼沒有返回值呢?Promise { <pending> }是什麼東西?
下面咱們先把Promise的基礎再看一遍。Promise在JS任務隊列裏面是當即執行的。好比boomerang(0)這個函數,是直接排在吃大蔥後面的。只是Promise的返回值是在將來返回的,若是你像這個代碼同樣想得到boomerang函數返回值是不行的,你只能獲得return new Promise返回的結果,一個正在等待的Promise。 那麼如何才能讓這個代碼正常工做呢?(獲得a,b,c的值) 咱們能夠用老派的then函數一頓then()而後進行處理(不推薦,代碼落後於時代並且太難看也容易出bug)。下面咱們用標準的async/await重寫一下:’優化

const world = async () => {
  console.log('吃大蔥');
  const a = await boomerang(0);
  console.log(a);
  const b = await boomerang(1000, 'reject').catch((e) => {
    return e.toString();
  });
  console.log(b);
  const c = await boomerang(2000);
  console.log(c);
  console.log('吃大蒜');
};
world();
複製代碼

這樣返回結果就對了。ui

吃大蔥
飛去來器0型號回來了
Error: 1000毫秒後爆炸
飛去來器2000型號回來了
吃大蒜
複製代碼

這樣的到了咱們想要的結果,並且咱們也對reject的函數正確地catch了錯誤。可是這個代碼雖然能夠正確執行,實際上仍是有一些問題的。問題在於,b的值須要等1秒,c的值須要等2秒,整個world()執行用了3秒。spa

如何繼續優化?

這裏面有3個Promise,實際上是能夠同步執行的。下面咱們就要引出Promise.all來對它們進行同步執行。改寫代碼以下:設計

const world = async () => {
  console.time('test');
  console.log('吃大蔥');
  const [a, b, c] = await Promise.all([
    boomerang(0),
    boomerang(1000, 'reject').catch((e) => {
      return e.toString();
    }),
    boomerang(2000),
  ]);
  console.log(a, b, c);
  console.log('吃大蒜');
  console.timeEnd('test');
};
world();
複製代碼

看一下執行結果:code

吃大蔥
飛去來器0型號回來了 Error: 1000毫秒後爆炸 飛去來器2000型號回來了
吃大蒜
test: 2005.940ms
複製代碼

因此在實際工做的代碼中,若是有多個Promise不是互相依賴的,要善用Promise.all來進行優化。你可能對於代碼中沒有catchPromise.all進行catch的錯誤抱有疑慮。其實在這裏若是咱們對a,b,c的函數調用進行了catch,就沒必要對Promise.all進行catch。這裏須要加深理解。orm

暫時先寫到這裏。可能還須要寫一下race什麼的。

相關文章
相關標籤/搜索