Skip to content

Instantly share code, notes, and snippets.

@Yama-Tomo
Last active December 18, 2021 14:10
Show Gist options
  • Save Yama-Tomo/75615688208d059cd9687ca1be5efb46 to your computer and use it in GitHub Desktop.
Save Yama-Tomo/75615688208d059cd9687ca1be5efb46 to your computer and use it in GitHub Desktop.
dataloaderの仕組みを理解するための簡易コード
function enqueuePostPromiseJob(fn) {
// Promise.resolve().then(fn)
// でも似たような動きになるが別のpromiseの解決に依存してexecを呼ばなければならない関数が同一の実行スケジュールから漏れてしまうため
// 次のフェーズの最速で呼ばれる nextTick で実行したほうが同一スケジュールでより多くの処理をすることができる。
// これをコメントインすると `dependOtherAsyncFuncExec` が別のバッチスケジュールで呼ばれることが確認できる
// フェーズについて: https://blog.hiroppy.me/entry/nodejs-event-loop
Promise.resolve().then(() => {
// nextTick の理由: https://github.com/graphql/dataloader/issues/180
process.nextTick(fn);
});
}
const batchObjects = [];
function availableBatchObj() {
const batchObj = batchObjects.find(o => !o.isDispatched);
if (batchObj) {
return batchObj;
}
const newBatchObj = {
isScheduled: false,
isDispatched: false,
resolves: [],
args: [],
};
batchObjects.push(newBatchObj);
return newBatchObj;
}
function exec(arg) {
const batchObj = availableBatchObj();
batchObj.args.push(arg);
if (!batchObj.isScheduled) {
batchObj.isScheduled = true;
enqueuePostPromiseJob(() => dispatch(batchObj));
}
return new Promise((resolve) => {
batchObj.resolves.push(resolve);
});
}
async function dependOtherAsyncFuncExec(arg) {
const val = await new Promise((r) => r(5));
return exec([arg, val]);
}
function dispatch(batchObj) {
batchObj.isDispatched = true;
console.log('複数の非同期関数を一括で解決:', batchObj.args);
for (let i = 0; i < batchObj.resolves.length; i++) {
batchObj.resolves[i](batchObj.args[i]);
}
}
async function main() {
const a = await exec(1);
printResult(a);
exec(2).then(printResult);
exec(3).then(printResult);
dependOtherAsyncFuncExec(4).then(printResult);
}
function printResult(val) {
console.log(` -> ${val}`);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment