Promise.allの制限はいくらですか?



How Much Is Limit Promise



解決:

V8 / V8エラーコードによるとTooManyElementsInPromiseすべてのソースコードオブジェクトPromise

T(TooManyElementsInPromiseAll、 'Promise.allに渡される要素が多すぎます')

この制限があります。 Promise.all、つまりC ++ PromiseAllには、次の概念があります。MaximumFunctionContextSlotsとkPromiseAllResolveElementCapabilitySlot、ここにソースコードからの最も興味深いものがあります:



// TODO(bmeurer):これをcontexts.hの適切なコンテキストマップに移動しますか? // awaitクロージャ用に導入したAwaitContextに似ています。 enum PromiseAllResolveElementContextSlots {//残りの要素数kPromiseAllResolveElementRemainingSlot = Context :: MIN_CONTEXT_SLOTS、// Promise.allからのPromise機能kPromiseAllResolveElementCapabilitySlot、// Promise.allからの値配列kPromiseAllResolveElementValuesArraySlot

私はここのようなエラースローを見ることを期待します

ThrowTypeError(context、MessageTemplate :: TooManyElementsInPromiseAll);

これが、TooManyElementsInPromiseAllエラー。私を正しい方向に向けてくれたクラレンスに感謝します!



BIND(&too_many_elements); {//要素が多すぎる(現在は2 ** 21-1を超える)場合は、//ここでRangeErrorを発生させます(これは直接キャッチされて拒否になります)//結果のpromiseの//。 //このケースも適切に処理し、//別の関数に移動して別のコンテキストを介してより大きなインデックスを渡すことで//この数を超える要素をサポートできますが、//これが必要になる可能性は低いようです。とにかく、システムの残りの部分が2 ** 21のライブPromiseをどのように処理するかは不明です。 Node * const result = CallRuntime(Runtime :: kThrowRangeError、native_context、SmiConstant(MessageTemplate :: kTooManyElementsInPromiseAll)); GotoIfException(result、&close_iterator、var_exception); Unreachable(); }

この制限のチェックはここにあります

//制限に達したかどうかを確認します。 TNode const index = var_index.value(); GotoIf(SmiEqual(index、SmiConstant(PropertyArray :: HashField :: kMax))、&too_many_elements);

だからkMaxは手がかりを解決するはずです!


V8ユニットテストから、次のことがわかります。



// Promise.allの要素の最大数をオーバーフローするときに// RangeErrorを適切にスローすることを確認します。これは// resolve要素にIDハッシュとしてインデックスを格納するため、現在2 ^ 21ビットに制限されています。閉鎖。 const a = new Array(2 ** 21-1); const p = Promise.resolve(1); for(let i = 0; i {assert.plan(1); Promise.all(a).then(assert.unreachable、reason => {assert.equals(true、reason instanceof RangeError);});});

要素の最大数は2 ^ 21(= 2097151)に制限されているようです。これは、他の回答が実行した実際のテストと一致しています。


私は言うことができます 限界はあるようですが、正確には特定できません どうして まさにそれがV8ソースコードのやり方です。私は次のコードを書きました(退屈している場合にのみ実行してください。しばらく時間がかかります)。

if(!window.chrome){throw new Error( 'これはChromiumでのみ試してください'); } // 1e6と1e7の間のどこかlettestAmountStart = 5.5e6; changeBy = 4.5e6とします。 const delay = ms => new Promise(resolve => setTimeout(resolve、ms)); const next =(testAmount)=> {changeBy = Math.ceil(changeBy / 2); if(changeBy === 1){console.log( 'done');戻る; } console.log( 'start' + testAmount); const proms = new Array(testAmount).fill(undefined); Promise.all(proms).then(()=> {//このループを完全にブロックしないようにする//ガベージコレクションの時間を与えるconsole.log(testAmount + ':OK'); delay(100).then(() => next(testAmount + changeBy));})。catch((e)=> {console.log(testAmount + ':' + e.message); delay(100).then(()=> next(testAmount --changeBy));}); }; next(testAmountStart);

結果:2097151要素の配列が渡されるとエラーがスローされますが、2097150要素はOKです:

const tryProms = length => {const proms = new Array(length).fill(undefined); Promise.all(proms).then(()=> {console.log( 'ok' + length);})。catch(()=> {console.log( 'error' + length);}); }; tryProms(2097150); tryProms(2097151);

したがって、2097150が限界です。 2097151が0x1FFFFFであるという事実と関係がある可能性があります。