# Promise API
在`Promise`類中,有 4 中靜態方法。我們在這里做下簡單介紹。
## [](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/04-promise-api/article.md#promiseresolve)Promise.resolve
語法:
~~~js
let promise = Promise.resolve(value);
~~~
根據給定的`value`值返回 resolved promise。
等價于:
~~~js
let promise = new Promise(resolve => resolve(value));
~~~
當我們已經有一個 value 的時候,就會使用該方法,但希望將它“封裝”進 promise。
例如,下面的`loadCached`函數會獲取`url`并記住結果,以便以后對同一 URL 進行調用時可以立即返回:
~~~js
function loadCached(url) {
let cache = loadCached.cache || (loadCached.cache = new Map());
if (cache.has(url)) {
*!*
return Promise.resolve(cache.get(url)); // (*)
*/!*
}
return fetch(url)
.then(response => response.text())
.then(text => {
cache[url] = text;
return text;
});
}
~~~
我們可以使用`loadCached(url).then(…)`,因為函數保證會返回一個 promise。這是`Promise.resolve`在`(*)`行的目的:它確保了接口的統一性。我們可以在`loadCached`之后使用`.then`。
## [](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/04-promise-api/article.md#promisereject)Promise.reject
語法:
~~~js
let promise = Promise.reject(error);
~~~
創建一個帶有`error`的 rejected promise。
就像這樣:
~~~js
let promise = new Promise((resolve, reject) => reject(error));
~~~
我們會在此討論它的完整性,但在實際工作中,我們很少這樣使用。
## [](https://github.com/javascript-tutorial/zh.javascript.info/blob/master/1-js/11-async/04-promise-api/article.md#promiseall)Promise.all
該方法并行運行多個 promise,并等待所有 promise 準備就緒。
語法:
~~~js
let promise = Promise.all(iterable);
~~~
它需要一個帶有 promise 的`iterable`對象,技術上來說,它是可以迭代的,但通常情況下,它只是一個數組,而且會返回一個新的 promise。新的 promise 是在所有 promise 都被解決并擁有一個存放結果的數組之后才出現的。
例如,下面的`Promise.all`在 3 秒之后被處理,然后它的結果就是一個`[1, 2, 3]`數組:
~~~js
Promise.all([
new Promise((resolve, reject) => setTimeout(() => resolve(1), 3000)), // 1
new Promise((resolve, reject) => setTimeout(() => resolve(2), 2000)), // 2
new Promise((resolve, reject) => setTimeout(() => resolve(3), 1000)) // 3
]).then(alert); // 1,2,3 when promises are ready: each promise contributes an array member
~~~
注意,它們的相對順序是相同的。盡管第一個 promise 需要很長的時間來解決,但它仍然是結果數組中的第一個。
常見技巧是將一組作業數據映射到一個 promise 數組,然后再將它們封裝進`Promise.all`。
例如,我們有一個存儲 URL 的數組,我們就可以像這樣來獲取它們:
~~~js
let urls = [
'https://api.github.com/users/iliakan',
'https://api.github.com/users/remy',
'https://api.github.com/users/jeresig'
];
// map every url to the promise fetch(github url)
let requests = urls.map(url => fetch(url));
// Promise.all waits until all jobs are resolved
Promise.all(requests)
.then(responses => responses.forEach(
response => alert(`${response.url}: ${response.status}`)
));
~~~
一個更真實的示例是通過用戶名來為 GitHub 用戶數組獲取用戶信息(或者我們可以通過他們的 id 來獲取一系列商品,邏輯都是一樣的):
~~~js
let names = ['iliakan', 'remy', 'jeresig'];
let requests = names.map(name => fetch(`https://api.github.com/users/${name}`));
Promise.all(requests)
.then(responses => {
// all responses are ready, we can show HTTP status codes
for(let response of responses) {
alert(`${response.url}: ${response.status}`); // shows 200 for every url
}
return responses;
})
// map array of responses into array of response.json() to read their content
.then(responses => Promise.all(responses.map(r => r.json())))
// all JSON answers are parsed: "users" is the array of them
.then(users => users.forEach(user => alert(user.name)));
~~~
如果任何 promise 為 rejected,`Promise.all`就會立即以 error reject。
例如:
~~~js
Promise.all([
new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
*!*
new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)),
*/!*
new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).catch(alert); // 錯誤:喔!
~~~
這里的第二個 promise 在兩秒內為 reject。這立即導致了對`Promise.all`的 reject。因此`.catch`被執行:避免 error 成為整個`Promise.all`的結果。
重要的細節是 promise 沒有提供 "cancel" 或 "abort" 執行方法。因此,其他 promise 會繼續執行,并最終為 settle,但它們的結果會被忽略。
有避免這種情況的方法:我們可以編寫額外的代碼到`clearTimeout`(或在出現 error 時取消)promise,或者我們可以將 error 作為結果數組中的成員顯示出來(參閱本章下的 task)。
````smart header="`Promise.all(iterable)`允許在 `iterable` 中無 promise" 通常 `Promise.all(iterable)` 接受可迭代的 promise(大多數情況是數組)。但如果這些對象中的任何一個不是 promise,它就會被封裝進 `Promise.resolve`。
例如。這里的結果是`[1, 2, 3]`:
~~~js
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000)
}),
2, // treated as Promise.resolve(2)
3 // treated as Promise.resolve(3)
]).then(alert); // 1, 2, 3
~~~
因此我們可以在方便的時候將非 promise 值傳遞給`Promise.all`。
~~~
## Promise.race
與 `Promise.all` 類似,所有的 promise 都是可迭代的,但不會等待所有都完成 —— 只等待第一個完成(或者有 error),然后繼續執行。
語法是:
```js
let promise = Promise.race(iterable);
```
例如,這里的結果回事 `1`:
```js run
Promise.race([
new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)),
new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).then(alert); // 1
```
因此,第一個結果/錯誤會成為整個 `Promise.race` 的結果。在第一個 promise "wins the race" 被解決后,所有的深層的結果/錯誤都會被忽略。
## 總結
`Promise` 類有 4 中靜態方法:
1. `Promise.resolve(value)` —— 根據給定值返回 resolved promise,
2. `Promise.reject(error)` —— 根據給定錯誤返回 rejected promise,
3. `Promise.all(promises)` —— 等待所有的 promise 為 resolve 時返回存放它們結果的數組。如果任意給定的 promise 為 reject,那么它就會變成 `Promise.all` 的錯誤結果,所以所有的其他結果都會被忽略。
4. `Promise.race(promises)` —— 等待第一個 promise 被解決,其結果/錯誤即為結果。
這四個方法中,`Promise.all` 在實戰中使用的最多。
~~~
- 內容介紹
- EcmaScript基礎
- 快速入門
- 常量與變量
- 字符串
- 函數的基本概念
- 條件判斷
- 數組
- 循環
- while循環
- for循環
- 函數基礎
- 對象
- 對象的方法
- 函數
- 變量作用域
- 箭頭函數
- 閉包
- 高階函數
- map/reduce
- filter
- sort
- Promise
- 基本對象
- Arguments 對象
- 剩余參數
- Map和Set
- Json基礎
- RegExp
- Date
- async
- callback
- promise基礎
- promise-api
- promise鏈
- async-await
- 項目實踐
- 標簽系統
- 遠程API請求
- 面向對象編程
- 創建對象
- 原型繼承
- 項目實踐
- Classes
- 構造函數
- extends
- static
- 項目實踐
- 模塊
- import
- export
- 項目實踐
- 第三方擴展庫
- immutable
- Vue快速入門
- 理解MVVM
- Vue中的MVVM模型
- Webpack+Vue快速入門
- 模板語法
- 計算屬性和偵聽器
- Class 與 Style 綁定
- 條件渲染
- 列表渲染
- 事件處理
- 表單輸入綁定
- 組件基礎
- 組件注冊
- Prop
- 自定義事件
- 插槽
- 混入
- 過濾器
- 項目實踐
- 標簽編輯
- iView
- iView快速入門
- 課程講座
- 環境配置
- 第3周 Javascript快速入門