LoginSignup
5
1

More than 1 year has passed since last update.

javascriptの非同期処理について理解する

Last updated at Posted at 2021-12-17

 そもそも同期処理とは

プログラムに記述された順序通りに実行される実行方式。

同期処理サンプルプログラム

synchronous.js
const calculate = () => {
    return 1 + 1
}

const message = "1+1="
const result = calculate()
console.log(message + result)

実行結果

$ node synchronous.js 
1+1=2

上の例は問題ないが、もしcalculate関数がとても時間のかかる処理であれば、ユーザーにとって大きな待ち時間が生まれる。
それを解決するために非同期処理が存在する。

非同期処理とは

タスクの実行完了を待たず、並行して次の処理を行う実行方式。
インターネットを通じて外部のデータを操作するとき(Web Apiを叩く)や、データベースにクエリを発行する際に利用される。
身近にある非同期処理が使われたサービスは、Google Mapである。Google Mapは地図の読み込み時にもユーザーは操作できる。
ここでは、非同期処理を使ってgithubの提供するAPIを叩いてユーザー名を取得させるプログラムを書いてみる。

非同期処理サンプルプログラム

asynchrounous.js
import fetch from 'node-fetch'

const getUserName = () => {
    const url = "https://api.github.com/users/XXXXXXXXX" //XXXXXXXにはgithubのユーザー名を入れてください

    fetch(url).then(res => res.json()) //非同期処理であるfetchメソッドで定義したurlからデータを取得して、取得したデータを引数(res)としてjsonメソッドでjson化する処理をthenメソッドでチェーン
        .then(json => { //成功時にres.json()の戻り値を引数(json)として処理を記述
            console.log("これは非同期処理成功時のメッセージです")
            console.log(json.login) //ユーザー名を表示
            return json.login //ユーザー名を戻り値としてgetUserNameにreturn
        }).catch(error => { //失敗時の処理
            console.log("これは非同期処理失敗時のメッセージです", error)
            return null
        })
};

const message = "githubユーザー名:"
const userName = getUserName()
console.log(message + userName)

実行結果

githubユーザー名:undefined
これは非同期処理成功時のメッセージです
XXXXXXXXXX

※XXXXXXXXにはgithubユーザー名が入ります。
githubユーザー名がundefinedと表示されてしまった。
これは、fetchが非同期で処理するメソッドであるために、getUserName関数の処理が完了してUserNameに結果が代入される前に`console.log(message+userName)実行されたからである。
これを解決するために、この非同期処理を、同期処理のように実行順序を制御する必要がある。
2通り方法がある。
Promiseを使う方法、async/awaitを使う方法である。
どちらの方法も非同期の処理が完了するまで次の処理に進まないようにしてくれるものである。

Promiseを使う方法

Promiseサンプルプログラム

promise.js
import fetch from 'node-fetch'

const getUserName = () => {
    return new Promise((resolve, reject) => { //new PromiseでPromiseのインスタンスを作成、その引数にresolve,rejectを引数にした非同期処理の関数を記述
        const url = "https://api.github.com/users/XXXXXXXX" //XXXXXXXにはgithubのユーザー名を入れてください

        fetch(url).then(res => res.json()) //非同期処理であるfetchメソッドで定義したurlからデータを取得して、取得したデータを引数(res)としてjsonメソッドでjson化する処理をthenメソッドでチェーン
            .then(json => { //成功時にres.json()の戻り値を引数(json)として処理を記述
            console.log("これは非同期処理成功時のメッセージです")
                console.log("非同期処理が成功")
                return resolve(json.login) //ユーザ名をreturn
            }).catch(error => { //失敗時
                console.log("非同期処理失敗", error)
                return reject(null)
            })
    })
};

const message = "githubユーザー名:"
getUserName().then(userName => { //成功すればthenメソッドが実行される。userNameにはgetUserName関数のjson.loginが入っている。
    console.log(message + userName)
}).catch(()=>{ //失敗すればcatchメソッドが実行される
    console.log("rejectしました")
})

実行結果

$ node promise.js 
非同期処理が成功
githubユーザー名:XXXXXXXXX

Promiseを使うことで非同期処理内(この例ではfetchメソッド以下)でresolveまたはrejectが出てくるまで次の処理に進まないようにしてくれる。

Promiseには3つの状態がある

Promiseには、PromiseStatusという3つのステータスがある。
* pending: 初期状態(未処理)
* resolved: 成功状態
* rejected: 失敗状態

new Promiseで作られたPromiseオブジェクトのPromiseStatuspending(初期状態)となり、成功した場合はresolved(成功状態)となり、失敗した場合、rejected(失敗状態)となる。resolvedの場合はthenメソッドが実行され、rejectedの場合はcatchメソッドが実行される。

async/await

async/awaitサンプルプログラム

AsnycAwait.js
import fetch from 'node-fetch'

const getAddress = async() => { //非同期処理を伴う関数定義時の引数をasync()にする
    const message = "githubユーザー名:"
    const url = "https://api.github.com/users/XXXXXXXX" //XXXXXXXにはgitのユーザー名を入れてください

    const json = await fetch(url) //非同期処理を伴う関数実行時にawaitをつける
        .then(res => { //成功時にfetchメソッドで取得したデータを引数として処理を記述
            console.log("非同期処理成功")
            return res.json() //resをjson化
        }).catch(error => { //失敗時の処理
            console.log("非同期処理失敗", error)
            return null
        });

    const userName = json.login //ユーザー名を代入
    console.log(message + userName)
}

getAddress()

実行結果

$ node AsyncAwait.js 
非同期処理成功
githubユーザー名:XXXXXXXX

非同期処理を伴う関数定義の引数をasync()にして、非同期処理を伴う関数実行時にawaitをつけることによって非同期処理が完了するまで次の処理に進まないようにしてくれる。

参考

【ES6】 JavaScript初心者でもわかるPromise講座
非同期処理の完了を待つ方法!Promise&async/await【分かりすぎて怖いJavaScript入門】

5
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
5
1