ES6原生Promise的全部方法介紹(附一道應用場景題目)

JS的ES6已經出來好久了,做爲前端工程師若是對此還不熟悉有點說不過去。不過若是要問,Promise原生的api一共有哪幾個?好像真的能夠難倒一票人,包括我本身也忽略了其中一個不經常使用的API Promise.race。咱們來瞧一下MDN對Promise的講解: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise前端

 

來看一下Promise的方法和prototype列表:api

【1】Promise.prototype.catch 在Promise被reject的時候觸發數組

【2】Promise.prototype.then 在Promise被resolve的時候觸發瀏覽器

【3】Promise.prototype.finally 不管Promise是否resolve仍是reject,都會觸發。請注意,這個是一個比較新的特性,大部分瀏覽器並無實現該特性。Promise.prototype.finally目前的瀏覽器兼容性列表以下:前端工程師

該特性還在Stage 3階段,等到在瀏覽器中大面積普及,估計要好久之後了。能夠採用第三方庫的實現,好比bluebird。async

【4】Promise.resolve 直接返回一個已經resolve的Promise實例ide

【5】Promise.reject 直接返回一個已經reject的Promise實例函數

【6】Promise.all 傳入一個Promise列表(常見的是由Promise組成的數組),只有當列表中全部的Promise都resolve時,該Promise纔會resolve,只要有一個reject,則該Promise會reject。url

【7】Promise.race 傳入一個Promise列表,其中第一個resolve的Promise會使得該Promise.race 最終 resolve,若是第一個完成的Promise是reject的,那麼Promise.race最終也reject(其實就是和跑的最快的那個Promise結果同樣~)。spa

 

其實Promise的原生API也就這麼幾個,其中Promise.all和Promise.race是最容易被忽略的兩個。我以前曾經不太熟悉Promise.race這個API致使實現一個需求卡住了好久。咱們來經過一個小的練習熟悉該API的用法吧。

 

附上一道題目:

假設目前有1000個url下載連接,已經存儲在數組url[1000]中(即url = ['http://example.com/video1.mp3', ...., 'http://example.com/video1000.mp3']),並且已經有一個函數function download,輸入一個url連接,返回一個Promise,該Promise在連接下載完成的時候resolve,下載失敗則reject。可是咱們要求,任意時刻,同時下載的連接數量不能夠超過10個。請寫一段代碼實現這個需求,要求儘量快速地將該1000個連接下載完成。

思路:聲明一個長度爲10的,由Promise組成的數組,用Promise.race作彙總,只要檢測到1個Promise resolve了,那就趕忙把那個Promise替換成一個新的再繼續下載。

const TotalTaskCount = 1000; // 一共有1000個連接
const MaxConcurrency = 10; // 同時下載的連接數最大不超過10
const url = [...]; // 1000個下載連接組成的數組
const download = function (urlStr) {
  // 返回Promise, 當下載完成的時候resolve
}

Answer:

let todoList = [];
let nextIndex = 0;
for (let j = 0; j < MaxConcurrency; j++) {
  let task = download(url[nextIndex]).then(() => {return j}); // 注意這裏resolve的值是任務在todoList的腳標,方便咱們在Promise.race以後找到完成的任務腳標
  todoList.push(task);
  nextIndex++;
}

const run = async function(todo) {
  let index = await Promise.race(todo); // 這裏index等於Promise.race第一個完成的任務的腳標
  if (nextIndex < TotalTaskCount) {
    todo[index] = download(url[nextIndex]).then(() => {return index;}); // 一旦有一個任務完成,立刻把他替換成一個新的任務,繼續下載
    nextIndex++;
  }
  await run(todo);
}

run(todoList);
相關文章
相關標籤/搜索