Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions testTranslators/testTranslators.js
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ async function init() {
allOutputView = new OutputView();
allOutputView.setDisplayed(true);

const whenReadyToRun = [];
await Promise.all(TRANSLATOR_TYPES.map(async displayType => {
let translatorType = displayType.toLowerCase();

Expand Down Expand Up @@ -474,7 +475,7 @@ async function init() {
// get translators, with code for unsupported translators
if(!viewerMode) {
let translators = await Zotero.Translators.getAllForType(translatorType, true);
haveTranslators(translators, translatorType);
whenReadyToRun.push(haveTranslators(translators, translatorType));

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 works, but it isn't very good IMO to depend on non-obvious promise behavior.

When you call a function that returns a promise, the code in that function starts executing immediately. It only pauses on the first await. In this case, it awaits pretty early on and we don't await anything in this function between here and the new Promise.all(), so everything works as expected, but that's pretty fragile. If haveTranslators() should only run once translatorTestViewsToRun is ready, we shouldn't call it at all until that's the case.

So instead we could do something like

whenReadyToRun.push({ translators, translatorType });

and below:

for (let { translators, translatorType } of whenReadyToRun) {
	await haveTranslators(translators, translatorType);
}

(That change also makes the different translator types run sequentially instead of in parallel, which is probably more what we want here.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

How about reverting this change, and simply do (pseudo-javascript)

return or await haveTranslators(translators, translatorType);

on this line? This too works, and it's shorter.

I think here, it's not that haveTranslators() has to run after translatorTestViewsToRun is ready. Actually haveTranslators() is the function that makes translatorTestViewsToRun ready by populating it.

The problems in init(), on the line 428 with await Promise.all(... big arrow function), is that the arrow function creates runaway promises. In each loop in .map() the async arrow function calls the promise-returning haveTranslators(), forgets about it, and immediately returns (a promise that resolves to) undefined. So the await Promise.all() doesn't wait for the promises that do the actual work, only the promises that initiate the work (results of calling the arrow function). That's why this await Promise.all(...) resumes prematurely.

}
}));

Expand Down Expand Up @@ -531,6 +532,7 @@ async function init() {
translatorBox.appendChild(lastP);

// Run translators specified in the hash params if any
await Promise.all(whenReadyToRun);
runURLSpecifiedTranslators();
}
}
Expand Down Expand Up @@ -650,4 +652,4 @@ function serializeToDownload(e) {
e.preventDefault();
}

window.addEventListener("load", load, false);
window.addEventListener("load", load, false);