From edb4e0664c221d3094365f552fd02820e0f8e238 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 16 Feb 2017 16:38:11 -0500 Subject: [PATCH] Walk dynamic module graph synchronously. I made this code asynchronous at first to accommodate the asynchronous cache API, but walking the graph needs to happen synchronously so that near-simultaneous dynamic import(...)s do not interleave. --- packages/dynamic-import/client.js | 53 ++++++++++++------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/packages/dynamic-import/client.js b/packages/dynamic-import/client.js index 215e6de197..2d96067a2d 100644 --- a/packages/dynamic-import/client.js +++ b/packages/dynamic-import/client.js @@ -18,56 +18,45 @@ Module.prototype.dynamicImport = function (id) { throw error; } - // Require the current module from the complete meta graph. + // Require the parent module from the complete meta graph. var meta = requireMeta(module.id); - var missingTree; - var localTree; + var versions = Object.create(null); function walk(meta) { - if (meta.dynamic) { - return meta.pending || (meta.pending = add( - meta.module.id, - meta.version - ).then(function () { - return allChildren(meta, walkChild); - })); + if (meta.dynamic && ! meta.pending) { + meta.pending = true; + versions[meta.module.id] = meta.version; + meta.eachChild(walkChild); } } - function add(id, version) { - return cache.check(id, version).then(function (code) { - addToTree(localTree = localTree || Object.create(null), id, code); - }, function (missing) { - addToTree(missingTree = missingTree || Object.create(null), id, 1); - }); - } - function walkChild(childModule) { return walk(childModule.exports); } - return allChildren(meta, walkChild, [id]).then(function () { + meta.eachChild(walkChild, [id]); + + var localTree; + var missingTree; + + return Promise.all(Object.keys(versions).map(function (id) { + return cache.check(id, versions[id]).then(function (code) { + addToTree(localTree = localTree || Object.create(null), id, code); + }, function (missing) { + addToTree(missingTree = missingTree || Object.create(null), id, 1); + }); + + })).then(function () { if (localTree) { installResults(localTree); } + return missingTree && fetchMissing(missingTree); + }).then(get); }); }; -// The allChildren iteration includes all child modules imported by -// meta.module, not just the child explicitly required here, so that -// implicit modules like package.json will be included too. -function allChildren(meta, callback, idsToRequire) { - var results = []; - // See meteor/packages/modules-runtime/meteor-install.js for the - // definition of meta.eachChild. - meta.eachChild(function (child) { - results.push(callback(child)); - }, idsToRequire); - return Promise.all(results); -} - function fetchMissing(missingTree) { return new Promise(function (resolve, reject) { Meteor.call(