Bug 1945994 - Explicitly block the load event until the cached script is executed. r=nbp,emilio
Differential Revision: https://phabricator.services.mozilla.com/D236980
This commit is contained in:
@@ -1335,6 +1335,45 @@ bool ScriptLoader::ProcessExternalScript(nsIScriptElement* aElement,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// https://html.spec.whatwg.org/#prepare-the-script-element
|
||||||
|
//
|
||||||
|
// Step 33. If el's type is "classic" and el has a src attribute, or el's
|
||||||
|
// type is "module":
|
||||||
|
// ...
|
||||||
|
// Step 33.2. If el has an async attribute or el's force async is true:
|
||||||
|
// Step 33.2.1. Let scripts be el's preparation-time document's set of
|
||||||
|
// scripts that will execute as soon as possible.
|
||||||
|
// Step 33.2.2. Append el to scripts.
|
||||||
|
// ...
|
||||||
|
// Step 33.3. Otherwise, if el is not parser-inserted:
|
||||||
|
// Step 33.3.1. Let scripts be el's preparation-time document's list of
|
||||||
|
// scripts that will execute in order as soon as possible.
|
||||||
|
// Step 33.3.2. Append el to scripts.
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// https://html.spec.whatwg.org/#the-end
|
||||||
|
//
|
||||||
|
// Step 7. Spin the event loop until the set of scripts that will execute
|
||||||
|
// as soon as possible and the list of scripts that will execute
|
||||||
|
// in order as soon as possible are empty.
|
||||||
|
//
|
||||||
|
// For scripts that creates the actual necko channel, the request is
|
||||||
|
// associated with the document's load group, and the load group manages
|
||||||
|
// the script set and the script list above implicitly, and the above
|
||||||
|
// "spin the event loop" is handled by IsBusy() check inside
|
||||||
|
// nsDocLoader::DocLoaderIsEmpty.
|
||||||
|
//
|
||||||
|
// https://searchfox.org/mozilla-central/rev/e85232b4b28ecc970240d39203e417d1c320623c/uriloader/base/nsDocLoader.cpp#704
|
||||||
|
//
|
||||||
|
// For in-memory-cached scripts, no channel is created, and those scripts
|
||||||
|
// should explicitly block the step 7 above.
|
||||||
|
//
|
||||||
|
// NOTE: IsAsyncScript represents both "async" and "force async".
|
||||||
|
if (request->GetScriptLoadContext()->IsAsyncScript() ||
|
||||||
|
parserMetadata == ParserMetadata::NotParserInserted) {
|
||||||
|
request->GetScriptLoadContext()->BlockOnload(mDocument);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,13 @@ support-files = [
|
|||||||
"counter_server.sjs",
|
"counter_server.sjs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
["browser_scriptCache_load_events.js"]
|
||||||
|
skip-if = ["!nightly_build"]
|
||||||
|
support-files = [
|
||||||
|
"file_scriptCache_load_events.js",
|
||||||
|
"page_scriptCache_load_events.html",
|
||||||
|
]
|
||||||
|
|
||||||
["browser_scriptCache_perf_timeline.js"]
|
["browser_scriptCache_perf_timeline.js"]
|
||||||
skip-if = ["!nightly_build"]
|
skip-if = ["!nightly_build"]
|
||||||
support-files = [
|
support-files = [
|
||||||
|
|||||||
56
dom/tests/browser/browser_scriptCache_load_events.js
Normal file
56
dom/tests/browser/browser_scriptCache_load_events.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
const TEST_URL =
|
||||||
|
"https://example.com/browser/dom/tests/browser/page_scriptCache_load_events.html";
|
||||||
|
|
||||||
|
function clearAllCache() {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
Services.clearData.deleteData(
|
||||||
|
Ci.nsIClearDataService.CLEAR_ALL_CACHES,
|
||||||
|
resolve
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testOrder() {
|
||||||
|
await clearAllCache();
|
||||||
|
|
||||||
|
const tab = await BrowserTestUtils.openNewForegroundTab({
|
||||||
|
gBrowser,
|
||||||
|
url: TEST_URL,
|
||||||
|
});
|
||||||
|
|
||||||
|
// The script should be executed in between DOMContentLoaded and load events.
|
||||||
|
|
||||||
|
// Uncached cache.
|
||||||
|
let result = await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
|
||||||
|
return content.document.getElementById("result").textContent;
|
||||||
|
});
|
||||||
|
is(result, "DOMContentLoaded+script+load");
|
||||||
|
|
||||||
|
await BrowserTestUtils.reloadTab(tab);
|
||||||
|
|
||||||
|
// Cached cache.
|
||||||
|
result = await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
|
||||||
|
return content.document.getElementById("result").textContent;
|
||||||
|
});
|
||||||
|
is(result, "DOMContentLoaded+script+load");
|
||||||
|
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(async function test_withoutNavigationCache() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [["dom.script_loader.navigation_cache", false]],
|
||||||
|
});
|
||||||
|
registerCleanupFunction(() => SpecialPowers.popPrefEnv());
|
||||||
|
|
||||||
|
await testOrder();
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_withNavigationCache() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [["dom.script_loader.navigation_cache", true]],
|
||||||
|
});
|
||||||
|
registerCleanupFunction(() => SpecialPowers.popPrefEnv());
|
||||||
|
|
||||||
|
await testOrder();
|
||||||
|
});
|
||||||
1
dom/tests/browser/file_scriptCache_load_events.js
Normal file
1
dom/tests/browser/file_scriptCache_load_events.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
document.getElementById("result").textContent += "+script";
|
||||||
20
dom/tests/browser/page_scriptCache_load_events.html
Normal file
20
dom/tests/browser/page_scriptCache_load_events.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>load events order test</title>
|
||||||
|
<script>
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
document.getElementById("result").textContent += "DOMContentLoaded";
|
||||||
|
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = "file_scriptCache_load_events.js";
|
||||||
|
document.getElementsByTagName("head")[0].appendChild(script);
|
||||||
|
});
|
||||||
|
function onLoad() {
|
||||||
|
document.getElementById("result").textContent += "+load";
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="onLoad()">
|
||||||
|
<span id="result"></span>
|
||||||
|
</body>
|
||||||
Reference in New Issue
Block a user