【Promise?】そろそろ調べるか・・【async/await!?】

# 時代についていけてない俺
非同期処理を書くときに、asyncモジュールを使っていた。

Promiseの話は聞いたことくらいはあった。
(僕の大好きなasyncモジュールはPromiseを使っているのかしら・・？)

いつの間にか、時代はasync/awaitだよ！
みたいなことになっていた。

そろそろ我も、基礎知識くらいはつけねば。

さらっと知りたい人も是非ご参考に。

※詳細までは説明してないので、さらなる知識をお求めの方はもっと良記事に行ってください。

# PureなJSで書く
ファイルの読み込みを行なって、
そこに記載されているファイルをさらに読み込む。
というコールバック地獄一歩手前のコード。

```js
fs.readFile('./next.txt', 'utf8', (err, nextFile) => {
  if ( err ) return console.log(err.message);

  fs.readFile(nextFile.trim(), 'utf8', (err, message) => {
    if ( err ) return console.log(err.message);
    console.log('Pure: ' + message);
  });
});
```

# asyncモジュールで書く
asyncモジュールを用いて、書き直したもの。
waterfallの第１引数のリストにメソッドを連ねていくことで、
直列っぽく書ける。

ホッとする。

```js
async.waterfall([
  done => {
    fs.readFile('./next.txt', 'utf8', (err, nextFile) => {
      if ( err ) return done(err);
      done(null, nextFile);
    });
  },
  (nextFile, done) => {
    fs.readFile(nextFile.trim(), 'utf8', (err, message) => {
      if ( err ) return done(err);
      done(null, message);
    });
  }
], (err, message) => {
  if ( err ) return console.log(err.message);
  console.log('async: ' + message);
});
```

# Promise
## Promiseまとめ
[参考1](http://numb86-tech.hatenablog.com/entry/2017/01/02/152517)
[参考2](http://tech.quartetcom.co.jp/2016/03/22/javascript-promise-05/)

|質問など|答え|
|:--|:--|
|Promiseって何？|Promiseは非同期処理の完了処理とその結果を表現する<br>→完了処理や結果を直列にかければ、callback地獄が避けられる！|
|完了処理？結果？|・Promiseは状態を持っている<br>・状態を変更する処理やその処理の結果のこと<br>(初期状態:pending、完了:fulfilled、失敗:rejected)|
|どうやって完了処理を書くの？|thenメソッドというのがあり、完了と失敗時のハンドラを登録できる|

```js:ここまでのまとめ
let p = new Promise((resolve, reject) => {
  return resolve(1);  // fulfilledなPromise{ <1> } になる
});

// 上記のresolveが、下記のcallbackになる
p.then((val) => console.log(val));  // 1
```

|質問など|答え|
|:--|:--|
|二つ分の非同期関数しか<br>書けないジャマイカ|基礎知識<br>・thenメソッドはPromiseを返す<br>・thenメソッドが返すPromiseは、thenに指定したハンドラの戻り値<br>→Promiseをreturnした場合：<br>そのPromiseをthenは返す<br>→値をreturnした場合:<br>その値をセットした、fulfilledなPromiseを返す<br>・↑のthenの特性をいかすと、メソッドチェーンが可能であり、コールバック地獄を同期的に書ける|
|Promise.resolveとか静的関数があるのだが？|Promise.resolve(val)は、fulfilledなPromiseのシンタックスシュガー|

## Promiseで書いてみた
見た目はasync.jsに似ているかも。

new Promiseがぱっと見、邪魔に見える。
でもわざわざ関数定義してそれを呼び出すのも・・。

```js
Promise.resolve()
.then(() => new Promise((resolve, reject) => {
  fs.readFile('./next.txt', 'utf8', (err, nextFile) => {
    if ( err ) return reject(err);
    return resolve(nextFile);
  });
}))
.then(nextFile => new Promise((resolve, reject) => {
  fs.readFile(nextFile.trim(), 'utf8', (err, message) => {
    if ( err ) return reject(err);
    return resolve(message);
  });
}))
.then(message => {
  console.log('Promise: ' + message);
})
.catch((err) => {
  console.log(err.message);
});
```

個人的につまづきポイントだったのが、
thenで指定したcallback(onFulfilled | onRejected)の処理に非同期関数を用いた場合、
非同期関数のcallbackでreturnした結果がPromiseに入ると思い込んでた件。
言ってて混乱するので下記参照。

```js:個人的つまづきポイント
.then(() => {
  fs.readFile('./next.txt', 'utf8', (err, nextFile) => {
　　　　　　　　// ここでthenのreturnがPromise{ <nextFile> }になると思い込んでしまった
    return nextFile;
　　　　});
});
```

考えたらすぐわかることだが、上記のreturnはcallbackの戻り値であり、
thenの戻り値ではない。

onFulfilledの戻り値は上記だとundefinedだし、これだとnextFileを
thenの戻り値とすることができない。
結果、Promise化するしかなくなる。

# (ES2017)async/await

## async/awaitまとめ
|質問など|答え|
|:--|:--|
|asyncって何さ|関数名にasyncをつけると、Promiseを返す関数となる|
|asyncつけるとどうなる？|・returnすると、その値を保持したfulfilledなPromiseを返す<br>・asyncFunctionでthrowすると、その値を保持したrejectedなPromiseを返す|

```js:ここまでのまとめ
let af = async () => 1;

console.log(af());  // Promise{ 1 }

af().then((val) => console.log(val));  // 1
```

|質問など|答え|
|:--|:--|
|awaitって何さ|・awaitは、asyncFunction内で使える<br>・Promiseを返す関数呼び出しの前にawaitをつけると、Promiseが解決するまで待ってくれる|
|何が便利？|awaitが指定された関数の戻り値はPromiseではなく、<br>**Promiseが完了した結果の値**を返す<br>→欲しい値を保持するPromiseを戻り値とする関数を作る<br>→awaitにする<br>→直列にかける！|

```js:awaitの戻り値について
(async () => {
  let noAwait = new Promise((resolve) => resolve(10));
  let awaitTest = await new Promise((resolve) => resolve(10));
  console.log(noAwait);    //  Promise{ 10 }
  console.log(awaitTest);  //  10
})();
```

## async/awaitで書いてみた
即時関数で書いたせいか、括弧がしゅごい。
ただ、そこを無視すれば、とても人間には読みやすくなりますね！

あと相変わらずnew Promiseが邪魔。

```js
(async () => {
  let nextFile = await(() => new Promise((resolve, reject) => {
    fs.readFile('./next.txt', 'utf8', (err, nextFile) => {
      if ( err ) return reject(err);
      resolve(nextFile);
    });
  }))();

  let message = await(() => new Promise((resolve, reject) => {
    fs.readFile(nextFile.trim(), 'utf8', (err, message) => {
      if ( err ) return reject(err);
      return resolve(message);
    });
  }))();

  console.log('async/await:', message);
})()
.catch((err) => console.log(err.message));
```

# new Promiseが邪魔な件
riawiththesamさんから頂いたコメントより。

callbackスタイルの関数をPromise化してくれる「promisify」というものがあります。
bluebird、es6-promisifyといったモジュールで実現できるほか、
Node.js8にはutilに追加されているそうです。

```js
const readFileAsync = require('util').promisify(fs.readFile);

(async () => {
  let nextFile = await readFileAsync('./next.txt', 'utf8');
  let message = await readFileAsync(nextFile.trim(), 'utf8');

  console.log('async/await:', message);
})()
.catch((err) => console.log(err.message));
```

ふ・・ふつくしい・・。