コールバックは同期プログラミングにおけるreturn文に相当するもので、非同期プログラミングでは必須となる、処理結果を通知するための関数である。
処理結果をreturn文ではなくコールバック関数の呼び出しという形で返すことで、結果を伝播させる手法を継続渡しスタイル(CPS:continuation-passing style)という。
function add(a, b, callback) {
callback(a + b)
}
console.log('before')
add(1, 2, result => console.log('result: ' + result))
console.log('after')
// 結果:
/**
* before
* result: 3
* after
*/
function addAsync(a, b, callback) {
setTimeout(() => callback(a + b), 100)
}
console.log('before')
addAsync(1, 2, result => console.log('result: ' + result))
console.log('after')
// 結果:
/**
* before
* after
* result: 3
*/
const fs = require('fs')
const cache = {}
// filenameから読み込んだデータをcallbackを呼び出して処理
function inconsistentRead(filename, callback) {
if (cache[filename]) {
// キャッシュがある場合は同期
callback(cache[filename])
} else {
// キャッシュがない場合は非同期
fs.readFile(filename, 'utf8', (err, data) => {
cache[filename] = data
callback(data)
})
}
}
function createFileReader(filename) {
const listeners = []
inconsistentRead(filename, value => {
listeners.forEach(listener => listener(value))
})
return {
onDataReady: listener => listeners.push(listener)
}
}
/* -------------------------------------------------------------------------- */
const reader1 = createFileReader('/Users/tomixy/myWorkSpace/TeX/JavaScript/Node_jsデザインパターン/sample/ch02/04_callback_unpredictable/data.txt')
reader1.onDataReady(data => {
console.log('First call data: ' + data)
// 同じファイルを再度読み込む
// この時点ではキャッシュが存在しているため、incosistentReadは即座に実行される
// しかし、まだlistenersが空なので、何も実行されない
const reader2 = createFileReader('/Users/tomixy/myWorkSpace/TeX/JavaScript/Node_jsデザインパターン/sample/ch02/04_callback_unpredictable/data.txt')
// ここでようやくlistenersを登録
reader2.onDataReady(data => {
console.log('Second call data: ' + data)
})
})
// 結果:
/**
* First call data: some data
*
*/
const fs = require('fs')
const cache = {}
function consistentReadSync(filename) {
if (cache[filename]) {
return cache[filename]
} else {
cache[filename] = fs.readFileSync(filename, 'utf8')
return cache[filename]
}
}
/* -------------------------------------------------------------------------- */
console.log(consistentReadSync('/Users/tomixy/myWorkSpace/TeX/JavaScript/Node_jsデザインパターン/sample/ch02/05_callback_sync_api/data.txt'))
console.log(consistentReadSync('/Users/tomixy/myWorkSpace/TeX/JavaScript/Node_jsデザインパターン/sample/ch02/05_callback_sync_api/data.txt'))
// 結果:
/**
* some data
*
* some data
*
*/