JavaScript　非同期処理

# はじめに

JavaScriptでは、並行処理がデフォルトです。処理が終わるまで待たずに次の処理を行うことができます。

```js
console.log('start')

setTimeout(() => {
  console.log('end')
}, 1000)

console.log('middle')
```

## Promise

JavaScriptでは、非同期処理の結果を受け取るために`Promise`というオブジェクトを使うことができます。
これによって逐次実行を行います。

```js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('end')
  }, 1000)
})

promise.then((value) => {
  console.log(value)
})
```

### Promiseオブジェクトの書き方

```js
const promise = new Promise((resolve, reject) => {
  // ここで非同期処理を行う
  // 成功したらresolve()を呼び出す
  // 失敗したらreject()を呼び出す
});
```

### Promiseオブジェクトの状態

- pending: 初期状態
- fulfilled: resolve()が呼ばれた状態
- rejected: reject()が呼ばれた状態

### Promiseオブジェクトの状態の確認

```js
promise.then(
  () => {
    // 成功したら呼ばれる
  },
  () => {
    // 失敗したら呼ばれる
  }
);
```

### Promiseオブジェクトのcatchメソッド

resolve()でもreject()でも呼ばれます。定義した関数内でthrowが行われたときに行う処理を定義します。

```js
promise.catch(() => {
  // 例外が出たら呼ばれる
});
```

### Promiseオブジェクトのfinallyメソッド

```js
promise.finally(() => {
  // 成功しても失敗しても呼ばれる
});
```

### 例

```js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const num = Math.random();
    if (num < 0.5) {
      resolve(num);
    } else {
      reject(num);
    }
  }, 1000);
});

promise
  .then(
    (num) => {
      console.log('成功', num);
    },
    (num) => {
      console.log('失敗', num);
    }
  )
  .catch((num) => {
    console.log('失敗', num);
  })
  .finally(() => {
    console.log('終了');
  });
```

結果

```
成功 0.15591197693529923
終了
```

### Promiseチェーン

```js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    // 四捨五入、小数点以下を切り捨て
    const num = Math.random() * 10 | 0;

    if (num < 5) {
      resolve(num);
    } else {
      reject(num);
    }
  }, 1000);
});

promise
  .then((num) => {
    console.log('1 成功', num);
    return num * 2;
  })
  .then((num) => {
    console.log('2 成功', num);
    return num * 2;
  })
  .then((num) => {
    console.log('3 成功', num);
  })
  .catch((num) => {
    console.log('失敗', num);
  })
  .finally(() => {
    console.log('終了');
  });
```

結果

```
1 成功 3
2 成功 6
3 成功 12
終了
```

### Promiseオブジェクトのallメソッド

Promiseの配列を受け取り、全てのPromiseが成功したら成功となるPromiseを返します。

```js
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('promise1');
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('promise2');
  }, 2000);
});

Promise.all([promise1, promise2]).then((values) => {
  console.log(values);
});
```

結果

```
["promise1", "promise2"]
```

## asyncとawait

Promiseのシンタックスシュガーです。
asyncはasynchronous(非同期的)の略で、非同期処理であることを示します。awaitは非同期処理が終わるまで待つことを示します。

```js
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('end')
  }, 1000)
})

promise.then((value) => {
  console.log(value)
})
```

上記のコードをasyncとawaitで書くと以下のようになります。

```js

const asyncFunc = async () => {
  const value = await promise
  console.log(value)
}

asyncFunc()
```

### async関数の書き方

async function キーワードは、式の中で async 関数を定義するために使用できます。

```js
const asyncFunc = async () => {
  // ここで非同期処理を行う
};
```

```js
async function asyncFunc() {
  // ここで非同期処理を行う
}
```

### async関数の戻り値

async関数はPromiseオブジェクトを返します。async関数の戻り値はPromiseオブジェクトのthenメソッドの引数であるresolveの引数になります。

```js
const asyncFunc = async () => {
  return 'end'
}

asyncFunc().then(value => {
  console.log(value)
})
```

### await演算子

await 演算子はプロミス (Promise) を待つために使用します。通常の JavaScript コードで、 async function の内部でのみ使用することができます。によって Promise が返されるのを待機するために使用します。

```js
const value = await promise;
```

## 参考

- [Promise - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- [非同期関数 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function)
- [await - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/await)