зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1312690: Load content scripts asynchronously when possible. r=aswan
MozReview-Commit-ID: BzpZA4stbCI --HG-- extra : rebase_source : 1b93f4ee7add989b3716b75c26ee9835e086d29c
This commit is contained in:
Родитель
fbd0e78bd4
Коммит
74012f4fcd
|
@ -39,6 +39,9 @@ interface mozIJSSubScriptLoader : nsISupports
|
|||
* - charset: specifying the character encoding of the file (default: ASCII)
|
||||
* - target: an object to evaluate onto (default: global object of the caller)
|
||||
* - ignoreCache: if set to true, will bypass the cache for reading the file.
|
||||
* - async: if set to true, the script will be loaded
|
||||
* asynchronously, and a Promise is returned which
|
||||
* resolves to its result when execution is complete.
|
||||
* @retval rv the value returned by the sub-script
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
|
|
|
@ -188,7 +188,32 @@ Script.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
tryInject(window, sandbox, shouldRun) {
|
||||
/**
|
||||
* Tries to inject this script into the given window and sandbox, if
|
||||
* there are pending operations for the window's current load state.
|
||||
*
|
||||
* @param {Window} window
|
||||
* The DOM Window to inject the scripts and CSS into.
|
||||
* @param {Sandbox} sandbox
|
||||
* A Sandbox inheriting from `window` in which to evaluate the
|
||||
* injected scripts.
|
||||
* @param {function} shouldRun
|
||||
* A function which, when passed the document load state that a
|
||||
* script is expected to run at, returns `true` if we should
|
||||
* currently be injecting scripts for that load state.
|
||||
*
|
||||
* For initial injection of a script, this function should
|
||||
* return true if the document is currently in or has already
|
||||
* passed through the given state. For injections triggered by
|
||||
* document state changes, it should only return true if the
|
||||
* given state exactly matches the state that triggered the
|
||||
* change.
|
||||
* @param {string} when
|
||||
* The document's current load state, or if triggered by a
|
||||
* document state change, the new document state that triggered
|
||||
* the injection.
|
||||
*/
|
||||
tryInject(window, sandbox, shouldRun, when) {
|
||||
if (!this.matches(window)) {
|
||||
this.deferred.reject({message: "No matching window"});
|
||||
return;
|
||||
|
@ -218,7 +243,9 @@ Script.prototype = {
|
|||
let options = {
|
||||
target: sandbox,
|
||||
charset: "UTF-8",
|
||||
async: false,
|
||||
// Inject asynchronously unless we're expected to inject before any
|
||||
// page scripts have run, and we haven't already missed that boat.
|
||||
async: this.run_at !== "document_start" || when !== "document_start",
|
||||
};
|
||||
try {
|
||||
result = Services.scriptloader.loadSubScriptWithOptions(url, options);
|
||||
|
@ -363,13 +390,13 @@ class ExtensionContext extends BaseContext {
|
|||
return this.sandbox;
|
||||
}
|
||||
|
||||
execute(script, shouldRun) {
|
||||
script.tryInject(this.contentWindow, this.sandbox, shouldRun);
|
||||
execute(script, shouldRun, when) {
|
||||
script.tryInject(this.contentWindow, this.sandbox, shouldRun, when);
|
||||
}
|
||||
|
||||
addScript(script) {
|
||||
addScript(script, when) {
|
||||
let state = DocumentManager.getWindowState(this.contentWindow);
|
||||
this.execute(script, scheduled => isWhenBeforeOrSame(scheduled, state));
|
||||
this.execute(script, scheduled => isWhenBeforeOrSame(scheduled, state), when);
|
||||
|
||||
// Save the script in case it has pending operations in later load
|
||||
// states, but only if we're before document_idle, or require cleanup.
|
||||
|
@ -380,7 +407,7 @@ class ExtensionContext extends BaseContext {
|
|||
|
||||
triggerScripts(documentState) {
|
||||
for (let script of this.scripts) {
|
||||
this.execute(script, scheduled => scheduled == documentState);
|
||||
this.execute(script, scheduled => scheduled == documentState, documentState);
|
||||
}
|
||||
if (documentState == "document_idle") {
|
||||
// Don't bother saving scripts after document_idle.
|
||||
|
@ -715,7 +742,7 @@ DocumentManager = {
|
|||
for (let script of extension.scripts) {
|
||||
if (script.matches(window)) {
|
||||
let context = this.getContentScriptContext(extension, window);
|
||||
context.addScript(script);
|
||||
context.addScript(script, when);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,26 +15,27 @@
|
|||
|
||||
add_task(function* test_contentscript() {
|
||||
function background() {
|
||||
browser.runtime.onMessage.addListener(([msg, expectedState, readyState], sender) => {
|
||||
browser.runtime.onMessage.addListener(([msg, expectedStates, readyState], sender) => {
|
||||
if (msg == "chrome-namespace-ok") {
|
||||
browser.test.sendMessage(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
browser.test.assertEq(msg, "script-run", "message type is correct");
|
||||
browser.test.assertEq(readyState, expectedState, "readyState is correct");
|
||||
browser.test.sendMessage("script-run-" + expectedState);
|
||||
browser.test.assertEq("script-run", msg, "message type is correct");
|
||||
browser.test.assertTrue(expectedStates.includes(readyState),
|
||||
`readyState "${readyState}" is one of [${expectedStates}]`);
|
||||
browser.test.sendMessage("script-run-" + expectedStates[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function contentScriptStart() {
|
||||
browser.runtime.sendMessage(["script-run", "loading", document.readyState]);
|
||||
browser.runtime.sendMessage(["script-run", ["loading"], document.readyState]);
|
||||
}
|
||||
function contentScriptEnd() {
|
||||
browser.runtime.sendMessage(["script-run", "interactive", document.readyState]);
|
||||
browser.runtime.sendMessage(["script-run", ["interactive", "complete"], document.readyState]);
|
||||
}
|
||||
function contentScriptIdle() {
|
||||
browser.runtime.sendMessage(["script-run", "complete", document.readyState]);
|
||||
browser.runtime.sendMessage(["script-run", ["complete"], document.readyState]);
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
|
|
|
@ -32,6 +32,7 @@ add_task(function* test_contentscript_context() {
|
|||
content_scripts: [{
|
||||
"matches": ["http://example.com/"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_start",
|
||||
}],
|
||||
},
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче