From be68fb8d2f9cbbd484b1f32cd135aa8820b3c15d Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sat, 4 Mar 2017 13:08:58 -0500 Subject: [PATCH] Call this.unblock() in __dynamicImport method. This prevents __dynamicImport from blocking other method calls made by the application, but introduces the possibility that __dynamicImport method results could be delivered out of order, which is now handled in the fetchMissing function. --- packages/dynamic-import/client.js | 25 +++++++++++++++++++++++-- packages/dynamic-import/server.js | 1 + 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/dynamic-import/client.js b/packages/dynamic-import/client.js index 647bdfee94..b6282fb6c4 100644 --- a/packages/dynamic-import/client.js +++ b/packages/dynamic-import/client.js @@ -58,13 +58,34 @@ Module.prototype.dynamicImport = function (id) { }); }; +// Results from fetchMissing must be delivered in the same order as calls +// to fetchMissing, because previous results may include modules needed by +// more recent calls. In practice, results are usually delivered in order, +// but might be delivered out of order because the __dynamicImport method +// calls this.unblock(). To achieve this ordering of results while still +// allowing parallel __dynamicImport method calls, we keep track of the +// most recent Promise returned by fetchMissing, and delay resolving the +// next Promise until the previous Promise has been resolved or rejected. +var lastFetchMissingPromise = delayPromise; + function fetchMissing(missingTree) { - return new Promise(function (resolve, reject) { + // Save the Promise that was most recent when fetchMissing was called. + var previousPromise = lastFetchMissingPromise; + + // Update lastFetchMissingPromise immediately, without waiting for + // the results to be delivered. + return lastFetchMissingPromise = new Promise(function (resolve, reject) { Meteor.call( "__dynamicImport", missingTree, function (error, resultsTree) { - error ? reject(error) : resolve(resultsTree); + if (error) { + reject(error); + } else { + resolve = resolve.bind(null, resultsTree) + // Continue even if previousPromise was rejected. + previousPromise.then(resolve, resolve); + } } ); }).then(installResults); diff --git a/packages/dynamic-import/server.js b/packages/dynamic-import/server.js index 569591f202..7f4ed98b9a 100644 --- a/packages/dynamic-import/server.js +++ b/packages/dynamic-import/server.js @@ -22,6 +22,7 @@ Object.keys(dynamicImportInfo).forEach(platform => { Meteor.methods({ __dynamicImport(tree) { check(tree, Object); + this.unblock(); const platform = this.connection ? "web.browser" : "server"; const pathParts = [];