iT邦幫忙

2022 iThome 鐵人賽

0
Modern Web

就是要搞懂 JavaScript 啦!系列 第 70

Day70 Async:Promise 方法

  • 分享至 

  • xImage
  •  

理解完 Promise 物件以後,這裡來看看 Promise 擁有的幾種方法,並在本文中分別介紹它們:

  • Promise.all()
  • Promise.race()
  • Promise.resolve()
  • Promise.reject()

Promise.all(iterable)

Promise.all() 接受一個可迭代的參數(比如 arraystring),大多時候是一個陣列,陣列內容可以為 Promise 物件或其他值,如果為 Promise 物件,在 Promise.all() 執行後會被展開。

Promise.all() 在陣列內所有值成功返回時成功,並回傳一個陣列,內部依序是原陣列的所有返回值。

若有任意 Promise 被拒絕時,Promise.all() 也會立刻拒絕,並獲得這個拒絕的失敗訊息。

Promise.all() 方法會返回所有展開後的 Promise 或非 Promise 的原始值,適合在需要一次取得多個 Promise 結果時使用:

Promise.all([
  // 成員一
  Promise.resolve(3),
  // 成員二
  1337,
  // 成員三
  new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'foo');
  })
]).then(values => {
  console.log(values); // [3, 1337, "foo"]
});

上面 setTimeout 的使用方式為 setTimeout( callback, delay, returnValue )

任意 Promise 被拒絕時 Promise.all() 也跟著立刻拒絕,並獲取錯誤訊息:

Promise.all([
  // 成員一
  Promise.reject("Be rejected."),
  // 成員二
  1337,
  // 成員三
  new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'foo');
  })
]).then(values => {
  console.log(values);
}).catch(err => {
  console.log(err); // Be rejected.
});

當傳入陣列為空時,同樣返回一個空陣列:

const p = Promise.all([])
  .then(values => {
    console.log(values); // []
  });

console.log(p) // Promise {<pending>} 

setTimeout(function () {
  console.log('the stack is now empty');
  console.log(p); // Promise {<fulfilled>: []}
});

Promise.race(iterable)

Promise.race 同樣接受一個可迭代的參數,陣列內容可為 Promise 物件或其他值,並且在任意 Promise 被拒絕時立即拒絕。

Promise.all 不同的是,Promise.race 只接受「第一個」完成並返回的值。傳入的陣列內容彼此之間是競爭關係,在出現第一位贏家後,其他的值就會被捨棄。

Promise.race([
  Promise.resolve(33),
  Promise.resolve(44)
]).then(val => {
  console.log(val); // 33
});

上面的 Promise.resolve(33) 直接就是完成狀態,因此在 Promise.race 收到它後立即就接受了這個結果,並捨棄了其他 Promise

下面來看看實際比賽搶快的 Promise.race

Promise.race([
  new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, "later")
  }),
  new Promise((resolve, reject) => {
    setTimeout(resolve, 500, "earlier")
  })
]).then(val => {
  console.log(val); // "earlier"
});

較早調用 resolve 返回的 "earlier" 勝出,成為最後唯一贏家。

其實不論成功或失敗,Promise.race 都只接受第一個解析完畢的結果(當然如果為失敗,就會進入拒絕流程):

// 解析為成功的 Promise 先抵達
Promise.race([
  new Promise((resolve, reject) => {
    setTimeout(resolve, 500, "resolved")
  }),
  new Promise((resolve, reject) => {
    setTimeout(reject, 1000, "rejected")
  })
]).then(
  val => {
    console.log(val); // "resolved"
  },
  err => {
    console.log(err);
  }
);

// 解析為失敗的 Promise 先抵達
Promise.race([
  new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, "resolved")
  }),
  new Promise((resolve, reject) => {
    setTimeout(reject, 500, "rejected")
  })
]).then(
  val => {
    console.log(val);
  },
  err => {
    console.log(err); // "rejected"
  }
);

另外,Promise.race 需要至少一名競賽的「跑者(racer)」,當傳入陣列為空時,它將永遠無法被完成:

const p = Promise.race([])
  .then(values => {
    console.log(values);
  });

console.log(p)
// Promise {<pending>} 

setTimeout(function () {
  console.log('the stack is now empty');
  console.log(p); 
});
// the stack is now empty
// Promise {<pending>}

Promise.resolve(value)

Promise.resolve(value) 會回傳一個解析狀態為成功的 Promise,完成的返回值為 value

Promise.resolve('Success')
  .then(function (value) {
    console.log(value); // "Success"
  });

由於 Promise 在傳入 thenable 物件(可以調用 then() 方法的物件)後會被解析展開,在不確定 value 是否為 Promise 物件,或者想將某個值作為 Promise 物件使用時,可以用 Promise.resolve 將其包裹起來。

var original = Promise.resolve(33);
var cast = Promise.resolve(original);
cast.then(function (val) {
  console.log(`value: ${val}`);
});
console.log('original === cast ? ' + (original === cast));

// original === cast ? true
// value: 33

Promise.reject(message)

Promise.reject(message) 會回傳一個解析狀態為失敗的 Promise,完成的返回訊息為 message

Promise.reject(new Error('fail'))
  .catch((err) => {
    console.log(err); // Stacktrace(Error: fail)
  });

參考資料


上一篇
Day69 Async:Promise 開篇
下一篇
Day71 Async:Generator
系列文
就是要搞懂 JavaScript 啦!73
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言