Skip to content
Prev Previous commit
Next Next commit
loader setup promise tweaks
  • Loading branch information
guybedford committed Feb 12, 2018
commit 5855e5ca839100fb8fb23d4b878e46ef61dc1708
54 changes: 30 additions & 24 deletions lib/internal/process/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,35 @@ function initializeImportMetaObject(wrap, meta) {
meta.url = wrap.url;
}

let loaderResolve, loaderReject;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, elaborating on what I wrote before:

let aResolve, aReject;
exports.loaderPromise = new Promise((resolve, reject) => {
  aResolve = resolve;
  aReject = reject;
});
trackedPromise.then(aResolve, aReject);

Can be written as:

let aResolve;
exports.loaderPromise = new Promise((resolve, reject) => {
  aResolve = resolve;
});
aResolve(trackedPromise);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could also just use createPromise/promiseReject/promiseResolve, no?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@devsnek that's technically true but I'm not sure it would help clean the code and that's an internal API - I doubt the cost of the extra closure here is worth it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked through this code at all, so take this with a grain of salt, but I recently did a lot of benchmarking on using the Promise constructor vs the internal createPromise/promiseReject/promiseResolve and the latter is definitely quite a bit faster.

But again, I don't know about the usage here, whether this is performance sensitive code, if these functions end up being user-land exposed, etc.

@devsnek devsnek Feb 12, 2018 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i just meant for readability heh, i was actually under the impression that the api was slower than the promise constructor

const loaderPromise = exports.loaderPromise = createPromise();
...
promiseResolve(loaderPromise, ESMLoader);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@devsnek @apapirovski not allocating a closure and it being faster is actually why we have this API to begin with (as well as util.promisify). There's a bit of history involved but if it wasn't faster I'd be surprised. That said - this code does I/O and the impact of an extra closure isn't something we should optimize for.

@devsnek I think it makes the code easier for people more familiar with promises in core to read but overall I personally prefer standard to nonstandard when we have the choice.

Namely, there are subtle differences between promiseResolve and resolve in the promise constructor which I'd rather avoid in areas that are not performance sensitive. I don't feel strongly about it though.

exports.loaderPromise = new Promise((resolve, reject) => {
exports.setup = function() {
setInitializeImportMetaObjectCallback(initializeImportMetaObject);

let ESMLoader = new Loader();
const loaderPromise = (async () => {
const userLoader = process.binding('config').userLoader;
if (userLoader) {
const hooks = await ESMLoader.import(
userLoader, getURLFromFilePath(`${process.cwd()}/`).href);
ESMLoader = new Loader();
ESMLoader.hook(hooks);
exports.ESMLoader = ESMLoader;
}
return ESMLoader;
})();
loaderPromise.then(resolve, reject);

setImportModuleDynamicallyCallback(async (referrer, specifier) => {
const loader = await loaderPromise;
return loader.import(specifier, normalizeReferrerURL(referrer));
});

exports.ESMLoader = ESMLoader;
};
loaderResolve = resolve;
loaderReject = reject;
});

exports.ESMLoader = undefined;

exports.setup = function() {
setInitializeImportMetaObjectCallback(initializeImportMetaObject);

let ESMLoader = new Loader();
const loaderPromise = (async () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a great pattern and errors here are suppressed unless explicitly asked for

const userLoader = process.binding('config').userLoader;
if (userLoader) {
const hooks = await ESMLoader.import(
userLoader, getURLFromFilePath(`${process.cwd()}/`).href);
ESMLoader = new Loader();
ESMLoader.hook(hooks);
exports.ESMLoader = ESMLoader;
}
return ESMLoader;
})();
loaderPromise.then(loaderResolve, loaderReject);

setImportModuleDynamicallyCallback(async (referrer, specifier) => {
const loader = await loaderPromise;
return loader.import(specifier, normalizeReferrerURL(referrer));
});

exports.ESMLoader = ESMLoader;
};