JavaScriptのPromiseについて part2

# 初めに
今回はプロミスの静的メソッド、コールバックの内部関数をプロミスへの変換について、気になるところをまとめていきたいと思います。

今回の参考文章はこちらです。
[Promise API - javascript.info](https://javascript.info/promise-api)
[Promisification - javascript.info](https://javascript.info/promisify)

# Promise API
## Promise.all(iterable)
<details><summary>使い方</summary><div>

- `iterable`：通常は`Promise`の入った配列。
- 配列に全ての`Promise`がresolveされるまで待ち（`fulfilled`状態）、新しい`Promise`オブジェクトを格納した配列を返す。（`then()`の引数となる）
</div></details>

<details><summary>注意点</summary><div>

- 配列にrejectされた`Promise`が出た場合、全体としてrejectされる。
    - 残りの`Promise`が実行するが、`Promise.all()`の返り値`Promise`はrejectになり、配列にほかに実行完了の`Promise`結果を無視する。
- `Promise.all()`は繰り返し可能の配列に`Promise`オブジェクトしか受け入れませんが、そうでない場合は`Promise.resolve()`でラップしたものと扱われる。
</div></details>

## Promise.allSettled(iterable)
<details><summary>使い方</summary><div>

- `iterable`：`Promise`オブジェクトを格納した配列。
- `Promise.allSettled()`はresolveされる（`fulfilled状態`）かrejectされる（`rejected`状態）に関わらず、すべての`Promise`オブジェクトが完了したら新しい`Promise`配列を返す。
- 配列にある各`Promise`オブジェクトから`.status`で状態をチェックしたり、履行した`Promise`なら`.value`から値を、拒否した`Promise`なら`.reason`からエラーオブジェクトを取得する。
</div></details>

## Promise.race(iterable)
```jsx
Promise.race([
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)),
  3,
  new Promise((resolve, reject) => resolve(4)),
]).then(result => {
  console.log(result)
})

// 3
```
<details><summary>使い方</summary><div>

- `iterable`：`Promise`オブジェクトを格納した配列。
- 最初の完了した値またはエラーを返します。それ以外は無視する。
</div></details>

## Promise.any(iterable)

<details><summary>使い方</summary><div>

- `iterable`：`Promise`オブジェクトを格納した配列。
- 最初の履行した（`fulfilled`）`Promise`を待ち、その結果を返す。
- すべての`Promise`が拒否（`rejected`）なら`AggregateError`エラーオブジェクトを返す。`errors`プロパティでエラーメッセージを取得できる。
</div></details>

## Promise.resolve(value)/reject(error)
<details><summary>使い方</summary><div>

- `value`：任意の値
- `Promise.resolve()`は値をラップし、解決（resolve）された`Promise`オブジェクトを返す。
- `Promise.reject()`で拒否（reject）されたエラーの`Promise`オブジェクトを返す。
</div></details>

# Promisification
callback関数から`Promise`を返す関数へ変換することです。

[　シンプルな例　](https://ja.javascript.info/promise-basics#loadscript)です。
```jsx
function loadScript(src, callback) {
  let script = document.createElement('script')
  script.src = src

  script.onload = () => callback(null, script)
  script.onerror = () => callback(new Error(`Script load error: ${src}`))

  document.head.append(script)
}
```
上はコールバック、下は`Promise`を返す。
```jsx
function loadScript(src) {
  return new Promise(resolve, reject => {
    let script = document.createElement('script')
    script.src = src

    script.onload = () => resolve(script)
    script.onerror = () => reject(new Error(`Script load error: ${src}`))

    document.head.append(script)
  })
}

let promise = loadScript('http://....')
promise.then(
  script => console.log(`${script.src} is loaded`),
  error => console.log(`Error: ${error.message}`)
)
```
基本的には関数を`Promise`でラップして、`Promise`の中にresolveかrejectを通して`Promise`オブジェクト（あるいはエラーオブジェクト）を生成させ、その結果を`then`チェーンへ渡すプロセスです。可読性を高め、コントロールもしやすくなる方法です。

ほかも[　このように　](https://ja.javascript.info/promisify)書き換えてもいいらしいです。
```jsx
let loadScriptPromise = function (src) {
  return new Promise((resolve, reject) => {
    loadScript(src, (err, script) => {
      if (err) {
        return reject(err)
      } else {
        resolve(script)
      }
    })
  })
}
```
`loadScript`は最初のコールバック`src`と`callback`（ここでは中身は`err`と`script`）、関数の結果が`Promise`を返すように全体を`Promise`でラップし、`err`が存在する場合は`reject()`を呼び出し`err`の結果を`Promise`で返すか、`resolve()`で`script`を返す。

しかし毎回のように書き直すにはさすがに手間がかかるし、ラッパーが必要であれば別の関数（ヘルパー）で`Promise`化してくれると楽になります。
```jsx
function promisify(f) {
  // at last, return the wrapped Promise to outside
  return function (...args) {
    return new Promise((resolve, reject) => {
      function callback(err, result) {
        if (err) {
          return reject(err)
        } else {
          resolve(result)
        }
      }

      // push the promisifying callback function to the end of args
      args.push(callback)

      // call the original function, set this promisifying function in it, and spread function in args
      f.call(this, ...args)
    })
  }
}
```
（このコード一番下についてどうしてこう書くのか充分に理解していません。憶測のうえ解釈が適切かどうかもわかりません。とりあえずメモとして残ります。）

関数`promisify`のすることが簡潔に言うと、`Promise`で`callback`関数をラップして返す。
`f`はもとの関数で、`args`は後からラップされた`callback`の保管場所で、この匿名関数では`Promise`でラップした関数を`args`の最後に入れて、`f`という元の関数に今にいる`Promise`環境を呼び出し、`args`で保管されている関数を展開して入れます。って言ってもとても理解しづらい解釈の仕方だと思いますが。

順番を変えて一番中から見ていくと、`Promise`でラップした関数を最後に`promisify()`の返り値匿名関数の引数に`callback`を入れておいて、それから`Promise`化したい関数`f`を`call`で強制的に今の`Promise`コンテキストに変えさせて、`f`関数の引数に、`args`に貯蔵した`callback`を展開して入れる。

説明では`f.call(this, ...args)`の作用は`callback`で結果を追跡するって書いてありますが、私にはちょっと難しすぎてまだ理解できていません...。
確かに`f`の環境が一時的に`Promise`化するために`call`が必要、`callback`も`Promise`環境に依存していると分かっています。でもどうやって結果を追跡できるのかまだわかりません。ちゃんと動かせる環境ができたら補足しようと思います。