多くの非同期操作を含むメソッドへの再帰呼び出しを処理する際に問題が発生する以下のプログラムがあります(実行可能にする必要があります)。Promise.all recursive
プログラムの出発点として、私はtest()
メソッドを持っています。それはroot
オブジェクト(ネストされた "要素"のツリー)を渡す_add()
への最初の呼び出しをトリガします。
メソッドは、storage
(ここでは単純な配列で表しています)に入れ子要素を追加します。これを行うために、私はすべての子要素でそれ自身を呼び出すように関数を記述しました。
要素の格納は非同期操作です。したがって、私は、すべての子要素の「まだ利用できない」値を保持するという約束を使用しています。
test()
で示されているように、ここでは同期を正しく処理できません。 add()
の最初の呼び出しによって返された約束が解決される前に、すべての要素がストレージに挿入されているはずです。これは、プログラムの出力が示すように、明らかにそうではありません。
もちろん、子のparentIdはその親のidを参照するので、格納操作は要素のツリーが探索されるのと同じ順序で行われることが重要です。
storage
から要素を取得しようとしたときに、まったく同じ種類の問題が発生することが予想されます。
ご協力いただければ幸いです。
ありがとうございます。
(() => {
const storage = [];
const root = {
_type: "root",
title: "root element",
gravity: null,
children: [
{
_type: "space",
title: "my first space",
gravity: 0,
children: [
{
_type: "bundle",
title: null,
gravity: 0,
children: [
{
_type: "vis",
title: "my first vis",
gravity: 0,
visualization: {
url: "http://dummyvis.com/#8766"
},
children: null
},
{
_type: "feature",
title: "my feature 1",
gravity: 1,
feature: {
componentType: "CPT_FEATURE1"
},
children: []
},
{
_type: "feature",
title: "my feature 2",
gravity: 1,
feature: {
componentType: "CPT_FEATURE2"
},
children: []
}
]
}
]
}
]
};
const store = (element, parentId) => {
return new Promise((resolve, reject) => {
storage.push({id:element.id, _type:element._type, gravity: element.gravity, parent:parentId, created_date:Date.now() });
setTimeout(() => resolve(element), 500);
});
}
const _add = (element, recurse, parentId) => {
console.log(element._type);
if(!element._type)
throw new Error("an element must declare a key '_type'");
parentId = parentId || null;
return new Promise((resolve, reject) => {
const promises = [];
promises.push(new Promise((resolve, reject) => {
store(element, parentId)
.then(element => {
resolve(element);
})
.catch(err => reject(err));
}));
Promise.all(promises)
.then(res => {
if(recurse && element.children.length > 0) {
element.children.forEach(child => {
_add(child, recurse, element.id);
});
}
resolve(element);
})
.catch(err => reject(err));
});
}
const test =() => {
_add(root, true)
.then(res => {
console.log("----------------------------------------------------------");
console.log("Test completed. Nothing should be printed after this line!");
console.log("------------------------------------------------------...-");
})
.catch(err => {
});
}
test();
})();
出力:
decisionspace
----------------------------------------------------------
Test completed. Nothing should be printed after this line!
------------------------------------------------------...-
bundle
visualization
feature
feature
は[ 'Promise'コンストラクタアンチパターン](http://stackoverflow.com/q/23803743/1048572?What-is-the-promise-constructionを避けてくださいそれは避けてください!) – Bergi