LoginSignup
10
10

More than 5 years have passed since last update.

JavaScriptにおける非同期処理の取り扱い

Posted at

はじめに

この記事ではJavaScriptにおける非同期処理の取り扱いを紹介します。

第0世代: sync

fsreadFileSyncのように一部のライブラリでは、非同期関数に加えて同期関数が用意されています。ビルドスクリプトのように高い処理性能が要求されない場面では、あえて非同期にしないというやり方も現実的な選択肢だと考えます。

メリット

  • 自然な記述が可能

デメリット

  • ブロックが発生する

'use strict';

var fs = require('fs')

var buffer = fs.readFileSync(__filename)
var text = buffer.toString()

console.log(text)

第1世代: callback

関数の呼び出し時に引数としてコールバック関数を指定します。コールバック関数は、処理終了時やエラー発生時に呼び出されます。現在のNode.jsにおける標準的な非同期の取り扱い方法です。

メリット
- とってもシンプル
- 大体いつでも使える(Node.js & ブラウザ)

デメリット
- 非同期処理が続くとインデントが深くなる
- 複数の非同期処理を扱うには工夫が必要

'use strict';

var fs = require('fs')

var buffer = fs.readFile(__filename, function (err, buffer) {
  if (err) {
    console.error(err.stack)
  }

  var text = buffer.toString()
  console.log(text)
})

第2世代: promise

Promiseというオブジェクトを生成し、thencatchなどのメソッドをつなげて記述するのが特徴です。深いインデントの解消や複数の非同期処理の並列実行が可能になる点などcallbackのデメリットを補うことができます。

メリット

  • 深いインデントの解消
  • Promise.all関数により複数の非同期処理の並列実行が可能

デメリット

  • コードを書く量が増える
  • Promiseを知らないと「?」となる
  • ブラウザではQbluebirdなどの外部ライブラリが必要

'use strict';

var fs = require('fs')

new Promise(function (resolve, reject) {
  fs.readFile(__filename, function (err, buffer) {
    err ? reject(err) : resolve(buffer)
  })
})
  .then(function (buffer) {
    var text = buffer.toString()
    console.log(text)
  })
  .catch(function (err) {
    console.error(err.stack)
  })

第3世代: yield

ES6のyieldキーワードとcoというライブラリによって実現されます。syncのわかりやすさとpromise並の細やかな制御が可能な点を兼ね備えています。

メリット
- 自然な記述
- promise並の細やかな制御が可能

デメリット
- co(function *() {})でくくる必要がある
- 知らない方にはpromise以上に「?」となる
- 基本的にブラウザでは使用できない(regeneratorを使うなど方法は有)

'use strict';

var fs = require('fs')
var co = require('co')

co(function *() {
  var buffer = new Promise(function (resolve, reject) {
    fs.readFile(__filename, function (err, buffer) {
      err ? reject(err) : resolve(buffer)
    })
  })

  var text = buffer.toString()
  console.log(text)
})
  .catch(function (err) {
    console.error(err.stack)
  })

co + Qが現状では使い勝手が良い

QというライブラリのQ.nfcallという関数を使用して、記述量をさらに減らすことができます。

'use strict';

var fs = require('fs')
var Q = require('q')
var co = require('co')

co(function *() {
  var buffer = Q.nfcall(fs.readFile, __filename)
  var text = buffer.toString()

  console.log(text)
})
  .catch(function (err) {
    console.error(err.stack)
  })

おわりに

状況に合わせて適切な非同期の取り扱いを!

10
10
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
10
10