1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptの非同期処理メモ

Last updated at Posted at 2023-10-12

はじめに

JavaScriptの非同期処理メモ

参考

まとめ

  • 前提としてJavaScriptはシングルスレッドのため非同期処理の終了まで停止して待たないノンブロッキング(待たない)である。
  • だが、非同期処理を複数考える場合、終了の順番によって、結果が常にランダムになる(終わる順番が保証されていない) -> 非同期処理を順番に実行したい
  • 非同期処理を順番に実行
    • コールバックで実現 -> Promiseのthenで実現 -> async/awaitで実現
  • TypeScriptで非同期処理を扱う場合はasync/awaitを利用する
  • async/awaitPromiseのシンタックスシュガーなため、Promiseは理解する

非同期処理とは

  • 多くの場合時間がかかる処理で、裏で行われるもの
  • 通信処理とかディスクアクセス処理とか

JavaScriptの非同期処理

JavaScriptの実行環境が、非同期処理についてはバックグラウンドで処理させて、次の処理に移れるような仕組みを持っている。
例えば、setTimeout関数は非同期処理なので、setTimeoutの処理終了をまたずに次の処理が実行される、など

JavaScript自体はシングルスレッドで動作する言語ですが、それを実行する環境(例: ブラウザやNode.js)は非同期処理をバックグラウンドでサポートする仕組みを提供しているはず

非同期処理に順序を付けたい場合

非同期処理関数のコールバック関数

  • 非同期処理の完了をコールバック関数で検知する仕組み
  • 非同期処理を順番に実行する場合、非同期処理にコールバック関数を渡していた。そして、コールバック関数の中に次の非同期処理とそのコールバックをネストする形で記述して順番通りに非同期処理を実行していた。コールバック関数を使わないと、非同期処理が終わった順番で実行されてしまう。
  • このコールバック関数の利用方法(コールバック関数の引数の数、型など)が各APIで違っていて、毎回調べる必要があった

しかし、非同期処理を重ねていくとネストがどんどん深くなってコードが見づらくなり、流れも追いにくくなります。これがコールバック地獄です。

Promise

  • Promiseを使った非同期処理の関数は、コールバック関数を引数に取るのではなくPromiseオブジェクトを返します
  • コールバック関数を使う場合は、API毎にコールバック関数をどのように渡すのか毎回調べる必要があったが、Promiseの使い方さえ覚えれば非同期処理を受け取れるようになった
    非同期処理を扱う使い方がそもそも便利になった↑
  • もちろん、thenをつなげることで簡潔に非同期処理を順番に連鎖させることができるようになった

Promiseをイメージする

Promiseは非同期処理そのものを表している

const p = new Promise<number>((resolve) => {
   // setTimeoutは非同期処理関数
   // ライブラリもここに非同期処理が記述されていて、その中でresolve()を利用しているはず
   setTimeout(() => {
      resolve(100);
  }, 3000);
});

p.then((num) => {
  console.log(num);
});
  • resolveは内部的に用意される関数で、非同期処理が終わったらresolveを呼び出されることを求められている。なのでここでは3秒後にresolve()している
  • resolve()が呼び出されると、Promiseが成功に解決される
  • 引数の関数は(resolve) =>{...} 即座に実行される
  • イメージ
    • 例えばfetchはPromiseを返すが、非同期処理が引数のURLの通信で、それは即座に実行されていて、通信が終わればresolve()を実行していて、Promiseのthenが呼べる状態になっているはず、、

さらに便利になったasync/await

  • 非同期処理をPromiseを意識しないで記述できるようになった。なので非同期処理を書く場合は大抵の場合async/awaitを記述すると思われる

  • async/awaitを使うと、より同期的な処理の書き方で非同期処理を順番に記述できるようになった

  • エラー処理もtyr-catch処理で記述することができる

  • asyncもawaitもPromiseを返すので、Promiseを理解していることが大事

  • awaitを使うと、asyncの関数が中断される、asyncの関数の次から実行される

function exampleFunction = async() => {
     // asyncの中でawaitを書くことで同期的に処理をかけるようになる
    console.log("Start of async function");

    const result = await new Promise((resolve) => {
        setTimeout(() => {
            resolve("Resolved after 2 seconds");
        }, 2000);
    });

    console.log(result);
    console.log("End of async function");
}

console.log("Before calling async function");
exampleFunction();
console.log("After calling async function");

表示

Before calling async function
Start of async function
After calling async function
Resolved after 2 seconds
End of async function
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?