2021年8月22日日曜日

JS:Nodeと非同期処理

NodeJSでは、パフォーマンスを優先するためにファイルやネットワーク、データベースの入出力など時間のかかる処理には非同期処理になる仕様になっている

同期処理に対応するために
「XXXXSync」の関数が用意されている

例えば
 fs.readFile() : ファイルを読み込む非同期処理

 fs.readFileSync() : ファイルを読み込む同期処理

const fs = require('fs')
// 同期処理
const data = fs.readFileSync('gggg.tat''utf-8')
console.log(data)
// 非同期処理
fs.readFile('gggg.tat''utf-8', readHandler)
function readHandler(err, data) {
  console.log(data)
}


無名関数

const fs = require('fs')

// 非同期処理
fs.readFile('gggg.tat''utf-8'function (err, data) {
  console.log(data)
})


アロー関数

const fs = require('fs')

// 非同期処理
fs.readFile('gggg.tat''utf-8', (err, data) => {
  console.log(data)
})


コールバック地獄

const fs = require('fs')

// 非同期処理
fs.readFile('a.tat''utf-8'function (err, data) {
  console.log('a.txtを読みました', data)
  fs.readFile('b.tat''utf-8'function (err, data) {
    console.log('b.txtを読みました', data)
    fs.readFile('c.tat''utf-8'function (err, data) {
      console.log('c.txtを読みました', data)
    })
  })
})


Promise対応

const fs = require('fs');

// Promise
function readFile_pr(fname) {
  return new Promise((resolve) => {
    fs.readFile(fname, 'utf-8', (err, s) => {
      resolve(s)
    })
  })
}

// テキストファイルを呼び込む
readFile_pr('a.txt')
  .then((text) => {
    console.log('a.txtを読みました', text)
    return readFile_pr('b.txt')
  })
  .then((text) => {
    console.log('b.txtを読みました', text)
    return readFile_pr('c.txt')
  })
  .then((text) => {
    console.log('c.txtを読みました', text)
  })


Generatorを使った場合

const fs = require('fs');

// 非同期処理の完了を待って関数の続きを呼び関数
function read_gfn(g, fname) {
  fs.readFile(fname, 'utf-8', (err, data) => {
    g.next(data)
  })
}

// Generator関数を定義する
// yieldで停止
const g = (function* () {
  const a = yield read_gfn(g, 'a.txt')
  console.log(a)
  const b = yield read_gfn(g, 'b.txt')
  console.log(b)
  const c = yield read_gfn(g, 'c.txt')
  console.log(c)
})()

g.next() // yieldとyieldとの間を実行


ES2017のasync/awaitを使った場合

// ES2017のasync/awaitを使った場合
const fs = require('fs');

// Promiseで非同期のファイルを読み込む処理
function readFileEx(fname) {
  return new Promise((resolve, reject) => {
    fs.readFile(fname, 'utf-8', (err, data) => {
      resolve(data)
    })
  })
}

// すべてのファイルを逐次読み込むasync関数を定義
async function readAll() {
  const a = await readFileEx('a.txt')
  console.log(a)
  const b = await readFileEx('b.txt')
  console.log(b)
  const c = await readFileEx('c.txt')
  console.log(c)
}

readAll()


ES2017ではプログラムが読みやすくなる