書いてから思ったのですが、下から読んだ方がいいかも。
Promise 以前の状況
例えば node.js で 'x' という名前のファイルの stat を取得したい場合
sample.js
const fs = require( 'fs' )
fs.stat(
'x'
, ( er, stat ) => {
if ( er ) console.error( er )
else console.log( stat )
}
)
という風にやってたと思います。
ファイルが複数の場合
複数のファイル、例えば 'x', 'y' という名前のファイルの stat を取得してから何かやりたいような場合、時間のかかる逐次処理でよければ
sample.js
const fs = require( 'fs' )
const
stats = []
fs.stat(
'x'
, ( er, stat ) => {
if ( er ) console.error( er )
else {
stats.push( stat )
fs.stat(
'y'
, ( er, stat ) => {
if ( er ) console.error( er )
else {
stats.push( stat )
console.log( stats )
}
}
)
}
}
)
並行にしたい場合はちょっと苦しいテクニックを使って
sample.js
const fs = require( 'fs' )
const
stats = [ null, null ]
fs.stat(
'x'
, ( er, stat ) => {
if ( er ) console.error( er )
else {
stats[ 0 ] = stat
if ( stats[ 1 ] ) console.log( stats )
}
}
)
fs.stat(
'y'
, ( er, stat ) => {
if ( er ) console.error( er )
else {
stats[ 1 ] = stat
if ( stats[ 0 ] ) console.log( stats )
}
}
)
のようにする必要がありました。ちょっと大変です。特にファイルの数が増えたりしたら。
Promise 以降
fs.stat を Promise 化すると上のような大変さがなくなります。
Promise 化
util.promisify を使う
sample.js
const fs = require( 'fs' )
const { promisify } = require( 'util' )
promisify( fs.stat )( 'x' ).then(
_ => console.log( _ )
).catch(
_ => console.error( _ )
)
素でやる
util.promisify がある今となってはもうやることはないと思いますが、参考までに。
sample.js
const fs = require( 'fs' )
new Promise(
( rs, rj ) => fs.stat(
'x'
, ( er, stat ) => er ? rj( er ) : rs( stat )
)
).then(
_ => console.log( _ )
).catch(
_ => console.error( _ )
)
ファイルが複数の場合
Promise.all を使う
Promise の配列を作って Promise.all に渡してやります。配列の中のすべての Promise が解決されるか、どれかがリジェクトされるまで待ちます。
sample.js
const fs = require( 'fs' )
const { promisify } = require( 'util' )
Promise.all(
[ 'x', 'y' ].map(
_ => promisify( fs.stat )( _ )
)
).then(
_ => console.log( _ )
).catch(
_ => console.error( _ )
)
関数化してみる
sample.js
const fs = require( 'fs' )
const { promisify } = require( 'util' )
const
Stats = files => Promise.all( files.map( _ => promisify( fs.stat )( _ ) ) )
Stats( [ 'x', 'y', 'z' ] ).then(
_ => console.log( _ )
).catch(
_ => console.error( _ )
)
最後に
Promise.all を使わない手はありませんね!