【JavaScript】非同期処理とはなんぞや


はじめに

JavaScriptの初心者を脱出して最初に躓くのは恐らく非同期処理な気がします。
自分も見事につまずいているので、記事にまとめながら勉強していきます。

非同期処理とは

処理を待たずにどんどん処理を進めていきます。
遅いやつを待ってあげるような優しい奴ではありません、非情です。

const fs = require('fs');

const file1 = fs.readFile('file1.txt')
const file2 = fs.readFile('file2.txt')
const file3 = fs.readFile('file3.txt')

console.log(`file1: ${file1}, file2: ${file2}, file3: ${file3}`)

動きません。

readFileは非同期処理です。file1君が処理を終えるのを待っているほどfile2君の気は長くありません。
それはfile3も同じです。結果として誰も成功できない。これが非同期処理です。

解決策

この誰も待ってくれない問題を解決する方法としてコールバックがあります。

const fs = require('fs');

fs.readFile("file1.txt", function (err, hoge) {
    fs.readFile("file2.txt", function (err, fuga) {
        fs.readFile("file3.txt", function (err, foo) {
            console.log(`file1: ${file1}, file2: ${file2}, file3: ${file3}`)
        });
    });
});

これならみんな終わるのを待ってくれる優しいやつになります。
しかし、今回は処理が3つなのでまだマシですが、これが5,6,...と増えると、俗にいうコールバック地獄に陥ります。

async awaitの登場

こんなコールバック地獄を解決してくれるのがasync awaitです。

const fs = require('fs');
const util = require('util');
// fs.readFileをPromise化
const readFileSync = util.promisify(fs.readFile);

async function readFiles(){
    var file1 = await readFileSync("file1.txt")
    var file2 = await readFileSync("file2.txt") 
    var file3 = await readFileSync("file3.txt") 
    console.log(`file1: ${file1}, file2: ${file2}, file3: ${file3}`)
}

readFiles()

asyncをつけられた関数は非同期処理を宣言し、Promiseを返すようになります。
awaitは、Promiseの処理が終わるまで待つようにするための処理です。
本来であれば、Promiseの処理がthenとcatchでチェーンしていきますが、awaitを使用することにより簡潔に書くことができますね。

ちなみに

最初のコードは readFile を readFileSync にすることで解決できます。

const fs = require('fs');

var file1 = fs.readFileSync("file1.txt")
var file2 = fs.readFileSync("file2.txt") 
var file3 = fs.readFileSync("file3.txt") 

console.log(`file1: ${file1}, file2: ${file2}, file3: ${file3}`)

async awaitを使いたかったので、util.promisifyを使用して無理やりasync awaitに組み込みました。

おしまい

JavaScript、まだまだ難しい部分がたくさんありますね。
非同期処理の概要を掴む際の参考になれれば幸いです。
何か指摘事項等ございましたら、コメントやTwitterなどでお願いします。

Twitter