以下のような状況を想定しています。
- 非同期でデータ取得をしたい
- 取得したデータに前処理をしてから使用したい
- 無駄な処理をしないように初回の結果を保存しておきたい
- 呼び出す側はそれを考えなくても使えるようにしたい
getDataClosure.js
/**
* 非同期のデータ取得処理
*/
const rawData = Promise.resolve("1,2,3");
/**
* 前処理
* @param {*} rawData
*/
const preprocessing = (rawData) => {
return rawData.split(",");
};
/**
* データを取得するクロージャを返す
* @param {*} rawData 元データ
* @param {*} preprocessing 前処理をする関数
*/
const getDataClosure = (rawData, preprocessing) => {
let data;
return () => {
console.log('get start');
if (typeof data === "undefined") {
// 前処理をする
return rawData.then((rawData) => {
console.log('preprocessing');
data = preprocessing(rawData);
console.log('get end');
return data;
});
} else {
// 前処理済だったらそれを返す
console.log('get end');
return Promise.resolve(data);
}
}
}
// 使用する
const dataClosure = getDataClosure(rawData, preprocessing);
const displayData = () => {
dataClosure().then((data) => {
console.log(data);
});
}
displayData();
setTimeout(displayData, 1000);
setTimeout(displayData, 2000);
実行結果
get start <- 初回の取得処理
preprocessing <- 初回なので前処理をする
get end
[ '1', '2', '3' ] <- 初回の取得結果
get start
get end <- 2回目は前処理をしていない
[ '1', '2', '3' ] <- 同じ結果が返ってくる
get start
get end
[ '1', '2', '3' ] <- 3回目も同様
上記の欠点
- 初回の処理が終わる前に2回目以降を呼び出すと前処理が動いてしまう
displayData();
displayData();
displayData();
get start
get start
get start
preprocessing
get end
preprocessing
get end
preprocessing
get end
[ '1', '2', '3' ]
[ '1', '2', '3' ]
[ '1', '2', '3' ]
もっといい書き方があるのだろうか。