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

[JS] 図で理解する 同期 / 非同期処理 の概念と実際の実装方法 - Promise, Generate, async

More than 1 year has passed since last update.

同期処理 / 非同期処理 とは

ここでは例として、
1. お風呂に入る
2. 洗濯機を回す
3. 洗濯物を干す
という処理を考えてみましょう。

すると、同期処理・非同期処理は下記のように表現することができます。
image.png

同期処理とは

同期処理はつまり、上から順番に処理を実行していきます。今回の例で説明すると、洗濯機を回す処理を開始したら、洗濯機が停止するまで何もしてはいけません。書かれている順番に処理が実行される、というプログラムの原則に則った書き方ですね。

さて、ここで注目して欲しいのは、各処理の主語です。書き出してましょう。

お風呂に入るのは? -> 私
洗濯をするのは? -> 洗濯機
洗濯物を干すのは? -> 私

つまり、洗濯機が頑張って洗濯物を洗ってくれている間、私というリソースが使用されずに放置されてしまうことになってしまいます。

非同期処理とは

ここで登場するのが非同期処理です。つまり、洗濯機が頑張って洗濯してくれている間にお風呂に入ってしまうのです。
洗濯が終わり、洗濯機が「ピーッピーッ」と終わった合図を出してくれてたら洗濯物を干す...という戦略です。
すると、リソースを無駄にすることなく行動、つまり処理を進めることができますよね。

JavaScriptに落とし込むと

    • JavaScript自体の処理
  • 洗濯機
    • 外部リソースとの連携作業
      • サーバーサイド処理、ファイル読み込み、Ajax処理... etc.

といった感じ。

非同期通信は処理の順番に気をつけろ!

非同期を行う際に重要になってくるのは、処理の順番を決めることです。
image.png

もし、洗濯が"終わったら"、というように処理を書かなかった場合、「洗濯物を干す」という処理が洗濯が終わる前に実行されてしまい、エラーになってしまいます。
image.png
 なので、「洗濯物を干す」という処理は、「洗濯機を回す」という処理が終わった後に実行されてほしい処理である、ということができます。

JavaScriptで実装してみよう

今回の処理

image.png

実際のコード

処理が実行されない例

/* ------------------
console.logに何も表示されないパターン
------------------ */
const fs = require('fs')

let result
fs.readFile('./src/1.txt', 'utf-8', (err, data) => {
  result = data
})
console.log(result)
fs.readFile('./src/2.txt', 'utf-8', (err, data) => {
  result = data
})
console.log(result)
fs.readFile('./src/3.txt', 'utf-8', (err, data) => {
  result = data
})
console.log(result)

実行結果

undefined
undefined
undefined

処理結果の順番がバラバラになる例

const fs = require('fs')

fs.readFile('./src/1.txt', 'utf-8', (err, data) => {
  console.log(data)
})
fs.readFile('./src/2.txt', 'utf-8', (err, data) => {
  console.log(data)
})
fs.readFile('./src/3.txt', 'utf-8', (err, data) => {
  console.log(data)
})

実行結果

this is 1

this is 3

this is 2

コールバック関数をうまく使う例

ここから、想定通りに動くコードの例です。

const fs = require('fs')

fs.readFile('./src/1.txt', 'utf-8', (err, data) => {
  console.log(data)
  fs.readFile('./src/2.txt', 'utf-8', (err, data) => {
    console.log(data)
    fs.readFile('./src/3.txt', 'utf-8', (err, data) => {
      console.log(data)
    })
  })
})

実行結果

this is 1

this is 2

this is 3

Promiseを活用する例

const fs = require('fs')

function rFilePromise (name) {
  return new Promise((resolve) => {
    fs.readFile(name, 'utf-8', (err, data) => {
      resolve(data)
    })
  })
}

rFilePromise('./src/1.txt')
  .then((text) => {
    console.log(text)
    return rFilePromise('./src/2.txt')
  })
  .then((text) => {
    console.log(text)
    return rFilePromise('./src/3.txt')
  })
  .then((text) => {
    console.log(text)
  })

Generateを使う例

const fs = require('fs')

function rFileGenerate (g, name) {
  fs.readFile(name, 'utf-8', (err, data) => {
    g.next(data)
  })
}

const g = (function * () {
  const one = yield rFileGenerate(g, './src/1.txt')
  console.log(one)
  const two = yield rFileGenerate(g, './src/2.txt')
  console.log(two)
  const three = yield rFileGenerate(g, './src/3.txt')
  console.log(three)
})()
g.next()

async, await の活用

const fs = require('fs')

function rFilePromise (name) {
  return new Promise((resolve) => {
    fs.readFile(name, 'utf-8', (err, data) => {
      resolve(data)
    })
  })
}

async function readText () {
  const one = await rFilePromise('./src/1.txt')
  console.log(one)
  const two = await rFilePromise('./src/2.txt')
  console.log(two)
  const three = await rFilePromise('./src/3.txt')
  console.log(three)
}

readText()
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
ユーザーは見つかりませんでした