---
# System prepended metadata

title: What is the extent of your experience with Promises and/or their polyfills?

---

# What is the extent of your experience with Promises and/or their polyfills?
### What is the extent of your experience with Promises

- Fetch: return 的東西就是一個 promise
- 後端用node.js接資料庫：mysql 在送 query 給資料庫時，因為要根據資料庫查詢結果做判斷，所以也做成 Promise 的形式，等待得到查詢結果後，再繼續做下一個判斷，最後再把處理完的結果送給前端

### Promises polyfills

Some common polyfills are `$.deferred`, Q.js and Bluebird but not all of them comply with the specification. ES2015 supports Promises out of the box and polyfills are typically not needed these days.

[Promise的实现类库（Library）](https://wohugb.gitbooks.io/promise/content/advanced/library.html)

---

# Promise的架構

## 什麼是 Promise

Promise 物件代表一個即將完成、或失敗的非同步操作，以及它所產生的值。
:::info
作為將來未知的回傳值的代理 (A promise serves as a proxy for a future value)
:::

## 為什麼要用 Promise

Promise 建構式主要用於包裹尚未支援 Promise 的函式。

## 建立 Promise

Promise 的 constructor 接收一個叫作”執行器函式（executor function）“的引數。此函式接收兩個函式作為引數。

第一個函式（`resolve`）在非同步作業成功完成時，以該作業之結果值被呼叫。

第二個函式（`reject`）在作業失敗時，以失敗訊息，通常是一個 error object，被呼叫。

```jsx
const myFirstPromise = new Promise((resolve, reject) => { //使用 new 建立 Promise 物件
  // 執行一些非同步作業，最終呼叫:
  //
  //   resolve(someValue); // 實現
  // 或
  //   reject("failure reason"); // 拒絕
});
```

## 讓一個函式具備 Promise 功能

讓它回傳一個 promise 即可

```jsx
function myAsyncFunction(url) { // myAsyncFunction 函式具備 Promise 功能
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
};
```

### 一個 `Promise` 物件處於以下幾種狀態：

- *擱置（pending）*：初始狀態，不是 fulfilled 與 rejected。
- *實現（fulfilled）*：表示操作成功地完成。
- *拒絕（rejected）*：表示操作失敗了。

當上述狀態轉換（`pending → fulfilled` 或 `pending → rejected`）發生時，那些透過 then 方法所關聯（associated）的處理函式就會依序被調用。

## 運用 Promise 的回傳值：使用 `then()`、`catch()`

- 透過呼叫 `then()` 來決定 `promise` 進入 `resolved` 時，要透過 `then()` 做什麼
- 或是進入 `rejected` 時，要透過 `catch()` 方法要做什麼

```jsx
'use strict';
var promiseCount = 0;

function testPromise() {
    let thisPromiseCount = ++promiseCount;

    let log = document.getElementById('log');
    log.insertAdjacentHTML('beforeend', thisPromiseCount +
        ') Started (<small>Sync code started</small>)<br/>');

    // 建立一個新的 promise：此 promise 承諾一個數值計數, 由 1 開始（等待約 2 秒）
    let p1 = new Promise(
        // 這個解決器函數（resolver function）呼叫實現或拒絕 promise。
        (resolve, reject) => {
            log.insertAdjacentHTML('beforeend', thisPromiseCount +
                ') Promise started (<small>Async code started</small>)<br/>');
            // 在此例子單純用來產生非同步特性。
            window.setTimeout(
                function() {
                    // 實現這個 promise!
                    resolve(thisPromiseCount);
                }, Math.random() * 2000 + 1000);
        }
    );

//----------- 上面是建立一個 Promise，下面是運用 Promise 的回傳值 -----------//

    // 接著透過呼叫 then() 來決定 promise 進入 resolved 時，要透過 then() 做什麼；或是進入 rejected 時，要透過 catch() 方法要做什麼。
    p1.then(
        // 印出實現值（fulfillment value）
        function(val) {
            log.insertAdjacentHTML('beforeend', val +
                ') Promise fulfilled (<small>Async code terminated</small>)<br/>');
        })
    .catch(
        // 印出失敗訊息（rejection reason）
        (reason) => {
            console.log('Handle rejected promise ('+reason+') here.');
        });

    log.insertAdjacentHTML('beforeend', thisPromiseCount +
        ') Promise made (<small>Sync code terminated</small>)<br/>');
}
```

### then() 的結構

`then()` 方法回傳的也是一個 Promise 物件（也可以不回傳）。

> then 方法回傳一個 Promise 而可以進行方法串接（method chaining）。
如果不回傳物件，則這個 Promise 的串接就結束了。

它接收兩個 argument： Promise 在**成功**及**失敗**情況時的回呼函式。

```jsx
promise.then(onFulfilled[, onRejected]); //兩個 argument
```

所以 then() 是可以用來處理 fulfillment 和 rejection 兩種狀況的。

```jsx
//處理 fulfillment 和 rejection 兩種狀況
promise.then(function(value) {
  // fulfillment
}, function(reason) {
  // rejection
});
```

### then() 的方法串接（method chaining）

```jsx
Promise.resolve('foo')
  .then(function(string) {
    return new Promise(function(resolve, reject) {  //then 方法回傳一個 Promise
      setTimeout(function() {
        string += 'bar';
        resolve(string);
      }, 1);
    });
  })
  .then(function(string) { 
    setTimeout(function() {
      string += 'baz';
      console.log(string);
    }, 1)
    return string; 
		//then 方法回傳一個 Promise：Promise.resolve(<value returned by whichever handler was called>)
  })
  .then(function(string) {  //then 方法不回傳
    console.log("Last Then:  oops... didn't bother to instantiate and return " +
                "a promise in the prior then so the sequence may be a bit " +
                "surprising");
    console.log(string);
  });
```

### rejection 的狀況不一定要用 `then()` 來處理：`catch()`

實務上，使用 catch 是較理想的。不建議使用兩個 argument 的 then 語法。

```jsx
Promise.resolve()
  .then( () => {
    throw 'Oh no!'; // Makes .then() return a rejected promise
  })
  .catch( reason => {
    console.error( 'onRejected function called: ', reason );
  })
  .then( () => {
    console.log( "I am always called even if the prior then's promise rejects" );
  });
```

## 補充

### `Promise` v.s. `async/await` 的轉換

- Promise：

```jsx=
function logFetch(url) {
  return fetch(url)
    .then(response => response.text())
    .then(text => {
      console.log(text);
    })
    .catch(err => {
      console.error('fetch failed', err);
    });
}
```

- Async/await：

```jsx=


async function logFetch(url) {
  try {
    const response = await fetch(url);  //promise 的 resolve(): 第一個 then()
    console.log(await response.text()); //promise 的 resolve(): 第二個 then()
  }
  catch (err) {
    console.log('fetch failed', err);
  }
}
```

```jsx=
const test = async function(url){
    const result = await logFetch(url); //等待一個結果
    //do something
}

test(); //可以不用加async

async function show(){
    await test(); //等待test回傳的結果
    //用那個結果 do something
}
```

- 參考資料

    [Promise - JavaScript | MDN](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Promise)

    [Promise.prototype.then() - JavaScript | MDN](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)

    [異步函數 - 提高 Promise 的易用性 | Web | Google Developers](https://developers.google.com/web/fundamentals/primers/async-functions?hl=zh-tw)