非同期処理の誕生背景とPromiseをまとめてみる

3 min read読了の目安(約3200字

背景

非同期処理やPromiseを学習し、一旦アウトプットしたかったため
記事として書いてみました。
最後まで読んで頂けると幸いです。

想定している読者

新人エンジニア向け。
非同期処理という言葉の意味やイメージはなんとなくあるが、具体的な仕組みやなぜ非同期通信が必要なのか、Promiseをどう使うのかは理解できていない人。

本文

まずは非同期処理がどうして生まれたかについて説明します。

1. 非同期処理の誕生


そもそもJavaScriptはシングルスレッドで処理を実行します。

シングルスレッドとは?
処理が単一に実行されることです。
1つの処理が終わってから、次の処理を実行します。
シングルスレッドのイメージ図↓

JavaScriptはシングルスレッドですので、めっちゃ時間のかかる処理(=以下、重い処理と記述)が実行されると、重い処理が終了してから以降の処理が実行されるため、非常に効率が悪いです。
このように効率の悪い処理の問題を解決するために、重い処理を非同期で処理する方法が誕生しました。

重い処理を非同期で実行するとどうなるのか

重い処理を非同期で実行することで、重い処理が完了するまでの間、別の処理を実行できます。

重い処理とは具体的に何か

を2つ紹介します。
これらは、非同期処理として実行する重い処理の例です。
・HTTP通信

fetch('https://jsonplaceholder.typicode.com/users')

・ストレージにデータを保存する処理

localStorage.setItem("key","value");

ストレージにデータを保存する処理は同期処理なので、非同期で処理したい場合は非同期処理へ変換する必要がある(= これをPromise化と言う)。
 Promise化に興味のある人はこちら>>> 参考サイト

2. Promiseとは


Promiseとは、処理が成功した時や失敗した時の値が確定していないオブジェクトです。

基本的に、Promiseは以下の3つから成り立ちます
・処理
・処理が成功した時の値
・処理が失敗した時の値

処理とは

1. 非同期処理の誕生で述べた重い(めっちゃ時間がかかる)処理のことです。

処理が成功した時の値

Promiseの値が正常に確定したら処理が成功します。
成功した際に実行して欲しい処理を.thenメソッドを使って登録できます。

処理が失敗した値

Promiseの値が意図したものに確定しなかったら、処理が失敗します。
失敗した際に実行して欲しい処理を.catchメソッドを使って登録します。

Promiseの実際の挙動

const result = fetch('apiのurl');
console.log(result);

とすると、コンソールには

promise(pending[待機])

と表示される。

fetch apiをコールすると、非常に遅いHTTPリクエストの結果がくるのを待たずにPromiseをreturnする。

通信が成功し、返ってきたPromiseの値を渡すには、次のようにthenメソッドを使います。

const result = fetch('apiのurl');
result.then(response => {
  console.log(response); // => 成功の結果がコンソールに表示される
})
console.log(result); // => pending[待機]のpromiseが返ってくる

失敗した時の値は次のようにcatchメソッドで受け取ります。

const result = fetch('apiのurl');
result.catch(error => {
  console.error(error); // => エラーオブジェクトがコンソールに表示される
})
console.log(result); // => pending[待機]のpromiseが返ってくる

Promiseを使うと何が嬉しいのか、、、

例:setTimeout関数 通常の書き方だと

setTimeout(function() {
  console.log('2秒経ったよ');
  setTimeout(function() {
    console.log('1.5秒経ったよ');
    setTimeout(function() {
      console.log('3秒経ったよ');
      setTimeout(function() {
        console.log('1秒経ったよ');
      }, 1000)
    }, 3000)
  }, 1500)
}, 2000)

非同期処理の中に非同期処理をネストして、非同期処理が順番に実行されるようにする。
すると、ネストが深すぎてコールバック地獄と呼ばれる状態になってしまう。
(英語でもコールバックヘル と呼ばれるらしい)
メンテナンスもしにくい。。。

一方で、Promiseを使うと

sleep(2000)
  .then(() => console.log('2秒経ったよ'))
  .then(() => sleep(1500))
  .then(() => console.log('1.5秒経ったよ'));
  .then(() => sleep(3000))
  .then(() => console.log('3秒経ったよ'));
  .then(() => sleep(1000))
  .then(() => console.log('1秒経ったよ'));  

ネストが浅くなり、処理も追加・削除しやすい。

これができる理由は、thenメソッドも新しいPromiseを返してくれるからです。
上記コードのように、thenで繋ぐコードをthenチェーンといいます。

終わり

最後までご閲覧頂きありがとうございました。
何かご不明な点、フィードバック等々ございましたら、遠慮なくコメントしていただけますと幸いです。

参考サイト

https://youtube.com/playlist?list=PL3PnJ18ZwZneYxvTkTGMgCh07OoTYlYw-