プロミスについて整理したことのまとめ

[Learning ECMAScript6](http://www.amazon.co.jp/381/dp/B012O8SE6C/ref=sr_1_fkmr0_1?ie=UTF8&qid=1446124237&sr=8-1-fkmr0&keywords=learning+ecmascript6) が参考書籍

## Promise はモナド
計算中かもしれない値を管理する文脈を持つモナド。
非同期操作を依存関係に従ってパイプライン化することでネストや処理の分離をなくし、コールバックやイベントを用いたコードよりも可視化性を高める。

プロミスはモナドである認識を持つことにより、多少 Haskell の知識がある自分としては、プロミスの必要性や位置付けを理解しやすくなった。

以降は、プロミスの仕様とメソッドの例などを整理している。
### The Promise Constructor

Promise コンストラクタは、Promise オブジェクトを作るために使われる。 Promise オブジェクトは非同期操作を表現するオブジェクト。

Promise コンストラクタには **executor** と呼ばれるコールバック関数を渡し、このexecutor には`resolve`と`reject`の二つのコールバック関数を渡す。

`resolve`/`reject`の実態は、その後`then()`で渡される処理が合成されたもの？なので、プログラマが明示的にこれらの関数を直接実装することはない。

### プロミスのステータス
プロミスオブジェクトのステータスは、次のように分類される。

|status|description|
|---|---|
|Fulfilled|`resolve`関数が、non-promise なオブジェクトとともに呼び出された時|
|Rejected|`reject`関数が呼び出されたり、executor のスコープで例外が発生した時|
|Pending|`resolve`や`reject`がまだ呼び出されていない状態|
|Settled|Pending ではない時([ref](http://www.2ality.com/2014/10/es6-promises-api.html))|


> Once a Promise is fulfilled or rejected, it cannot be transitioned back. An attempt to transition it will have no effect.
一度 **Fulfilled** または **Rejected** になると、その状態を戻すことはできない。やろうとしても、何も起きない。

プロミスの特徴として、`resolve`関数に Promise オブジェクトが渡った場合、元のオブジェクトのステータスは渡されたオブジェクトのステータスに依存することになる。

```javascript
// プロミスにプロミスを渡す
let a = new Promise(function (resolve, reject) {
  let b = new Promise(function (res, rej) {
    setTimeout(function () {
      res(100);
    }, 1000);
  });
  resolve(b);
});

a
  .then(function (value) {
  console.log('the value fulfilled is ' + value);
  return value * 3; // return the value multiplied 3
})
  .then(function (value) {
    console.log('the value passed by previous then is :' + value);
  });
```

### The then(onFulfilled, onRejected) method

> The callbacks passed to the then() method are executed asynchronously.
`then`に渡されるコールバック関数は非同期処理となる。

> The then() method always returns a new promise object, which resolves the return value of the calling callback.
`then`は必ず promise object を返し、このオブジェクトは渡されたコールバック関数が`return`した値を`resolve`する。

### The catch(onRejected) method
`then(null, onRejected)`のシンタックスシュガー。

```javascript
promise.then(null, function(reason){
});
```

```javascript
promise.catch(function(reason){
});
```

`catch`も promise object を返し、、このオブジェクトは渡されたコールバック関数がreturnした値を`resolve`する。つまり、さらに`then`よるチェーンを作ることができる。

```javascript
let a = new Promise(function (resolve, reject) {
  let b = new Promise(function (res, rej) {
    setTimeout(function () {
      rej(100);
    }, 1000);
  });
  resolve(b);
});

a
  .then(function (value) {
  console.log('the value fulfilled is ' + value);
  return value * 3; // return the value multiplied 3
})
  .catch(reason => {
    console.log('error : ' + reason);
    return reason;
  })
  .then(value => { // チェーン可能。onRejectの返り値を引数にとっている
    console.log('re:value: ' + value);
  });
```


## モナドっぽい雰囲気
普通の値を、プロミスという文脈に包む関数が用意されている。

### The Promise.resolve(value) method

> The resolve() method is basically used to convert a value to an promise object. It is useful when you find yourself with a value that may or may not be a Promise, but you want to use it as a Promise.For example, the jQuery Promises have different interfaces than the ES6 Promises. Therefore, you can use the resolve() method to convert the jQuery Promises into the ES6 Promises.
これから使おうとしている値が promise object かどうかわからない時、これを使うとプロミスで包むことができる。

### The Promise.reject(value) method
主にデバッグ目的で利用する。値をプロミスで包むため、という使われ方はしない。

### The Promise.all(itearable) method
iterable オブジェクトの中の promise object が全て fulfill されると、このpromise object も fulfill される。

### The Promise.race(iterabe) method

> The the race() method of the Promise object takes an iterable object as the argument and returns a Promise that fulfills or rejects as soon as one of the Promises in the iterable object is fulfilled or rejected, with the fulfillment value or reason from that Promise.

iterable オブジェクトの中の promise object のうち、最も早く **settled** となったオブジェクトが返る。以降、その他のオブジェクトも `race`の制御とは無関係に`resolve` されていく。

```javascript
let p1 = new Promise(function(resolve, reject){
  setTimeout(function(){
    resolve("Fulfillment Value 1");
  }, 1000);
});

let p2 = new Promise(function(resolve, reject){
  setTimeout(function(){
    reject("fulfillment Value 2");
  }, 2000);
});

var arr = [p1, p2];

Promise.race(arr).then(function(value){
  console.log('onFulfilled: ' + value); //Output "onFulfilled: Fulfillment Value 1"
}, function(reason){
  console.log('onRejected: ' + reason);
});

```