Help us understand the problem. What is going on with this article?

JavaScriptの非同期処理はasync/await/Promise

JavaScriptの非同期処理についてまとめた

今週からモダンなJavaScriptを使った開発案件にjoinすることになりました。
JavaScriptなら専門学校でも勉強したしいける!と思っていましたが、最近のJavaScriptは色々と複雑なうえに、そもそも入門レベル(苦笑)しか無かったので改めて勉強しようとおもいました。

今回は同期処理と非同期処理の違い、そして非同期処理の取り扱い方について書いていきます。

同期処理と非同期処理

  • 同期処理(sync)・・・コードを順番に処理していき、ひとつの処理が終わるまで次の処理をしない
  • 非同期処理(async)・・・処理が終わるのを待たずに次の処理をする

同期処理

test.js
const a = () => console.log("a");
const b = () => console.log("b");
const c = () => console.log("c");

a()
b()
c()
実行結果
a
b
c

普通に書くと上から順番に実行されます。これが同期処理です。a→b→cの順番で書いてあるわけですから、実行結果がその順番になるのは当然です。

非同期処理

test2.js
const a = () => console.log("a");
const b = () => {
  setTimeout(() => {
    console.log("b")
  }, 1000);
}
const c = () => console.log("c");

a()
b()
c()
実行結果
a
c
b

次にbの処理を書き換え、実行されて1秒待ってからbを表示するようにしました。

setTimeout関数は、第一引数に関数、第二引数に時間(ミリ秒)をとります。そして第二引数の時間経過後に第一引数を実行します。上のように第一引数の中に関数をぶち込んでもいいし、別で定義しても構いません。

結果a→b→cの順番で呼び出したのに、コンソール上の結果はa→c→bの順番になってしまいました。何が起きたのかというと、bの中にあるsetTimeout関数の結果を待たずに次のcが実行されたのです。
setTimeout関数のように、実行結果を待たずに次の処理が実行されてしまうものを非同期処理といいます。書いた順番と違った順番で処理される可能性があるわけですね。

それでも「俺はこの順番に実行したいんじゃー」という時があるとおもいます。例えばあるデータを外部から取ってきて計算したい場合、データが返ってくる前に計算は不可能ですよね。時間がかる処理があっても決まった順番に処理したい場合は以下のような対策があります。

Promise

test3.js
const a = () => console.log("a");
const b = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("b")
      resolve();
    }, 1000);
  });
}
const c = () => console.log("c");

a()
b().then(c)
実行結果
a
b
c

これで無事解決です。

ポイントはPromiseインスタンスを生成して返却する点です。
Promiseは関数を引数にとりますが、その関数の第一引数にresolve、第二引数にreject(省略可)の2つのコールバック関数をとります。この2つの名前は適当でもいいです。そして処理の成功時はresolveメソッドを実行してあげます。

あとは実行時にthenメソッドを実行し、引数に次に実行したい関数を入れれば完成です。

test4.js
//実行部分
a()
b().then(c).catch(d)

もし「外部にデータを取りに行ったけど、データが取ってこれませんでした」という時には、resolveメソッドではなくrejectメソッドを実行してあげてください。データが取れたかどうかで条件分岐すると良いですね。そしてthenメソッドの次にcatchメソッドを書き加えればOKです。

上の例は成功すればc、失敗ならdを実行します。

async/await

test5.js
const abc = async() => {
  const a = () => console.log("a");
  const b = () => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log("b")
        resolve();
      }, 1000);
    });
  }
  const c = () => console.log("c");

  a()
  await b()
  c()
}

abc();
実行結果
a
b
c

1行目ですが、今までの処理を関数abcでまとめて、asyncを付けました。
asyncを付けた関数は必ずPromiseインスタンスを返します。そしてasync関数内ではawait を使えます。こうすることでawaitが付けられた関数の処理を待ってから次の処理を行います。thenをつなげて書くよりも、見た目が同期処理っぽく書けるのが良い点です。

まとめ

JavaScriptの非同期処理はasync/await/Promise♪(タイトル回収)

参考

js-prime 非同期処理 https://jsprimer.net/basic/async/

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした