From 0434b133a2ce52a6e219189a74bdfa5090b63954 Mon Sep 17 00:00:00 2001 From: Austin Seipp Date: Fri, 5 Jan 2024 19:22:25 -0600 Subject: [PATCH] fix(api-base): resolve resource promises in parallel Summary: When fetching built-in resources (e.g. techlibs) for the virtual filesystem, do it in parallel by building up an array of promises and resolving them via `Promise.all`, rather than doing so sequentially. A nice effect of this is that it helps avoid HOL blocking when the resource might be non-local e.g. your in-browser HTTP request to a CDN or server suddenly starts having bad latency. It also lets us get away with less logging (ref: #2), and removing these explicit `console.log` calls actually fixes an awkward case where `printLine` is set to a no-op function to keep things quiet, but these logs would still get output with no way to suppress it. (If this is ever brought back it should at least respect the `printLine` callback.) Fixes #2. Signed-off-by: Austin Seipp Change-Id: Ie8085a216c22576d6956f007e2859e2381a56a12 --- lib/api-base.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/api-base.js b/lib/api-base.js index 4019d38..a2bafc9 100644 --- a/lib/api-base.js +++ b/lib/api-base.js @@ -50,7 +50,6 @@ export class BaseApplication { async _fetchResources() { // Async import, to allow inlining some of the resources within resource file. - console.log(`[YoWASP runtime] Fetching resource bundle ${this.resourceFileURL}`); const { modules, filesystem } = await import(this.resourceFileURL); return { modules: await this._fetchObject(modules, this._fetchWebAssembly), @@ -60,16 +59,21 @@ export class BaseApplication { async _fetchObject(obj, fetchFn) { // Mutate the object being fetched, to avoid re-fetches within the same session. + // Do this in parallel to avoid HOL blocking. + const promises = []; for (const [key, value] of Object.entries(obj)) { if (value instanceof URL) { - console.log(`[YoWASP runtime] Fetching resource file ${value}`); - obj[key] = await fetchFn(value); + promises.push(fetchFn(value).then((fetched) => [key, fetched])); } else if (typeof value === "string" || value instanceof Uint8Array) { - obj[key] = value; + promises.push(Promise.resolve([key, value])); } else { - obj[key] = await this._fetchObject(value, fetchFn); + promises.push(this._fetchObject(value, fetchFn).then((fetched) => [key, fetched])); } } + + for (const [key, value] of await Promise.all(promises)) + obj[key] = value; + return obj; }