当我在Firefox下的沙盒Greasemonkey脚本中将jQuery延迟对象传递给窗口事件处理程序时,由于某种原因,resolve
函数未定义。
考虑以下测试用户脚本,它必须在已加载jQuery的页面上运行(这是我可以获得的最小值):
// ==UserScript==
// @name Deferred Event Test
// @namespace jasonc
// @description Deferred Event Test
// @include /https?:\/\/*/
// @version 1
// @grant GM_getValue
// @run-at document-idle
// ==/UserScript==
// Event listener calls ev.detail.deferred.resolve().
window.addEventListener('test-event-1234', function (ev) {
try {
console.log(ev.detail.deferred);
console.log(ev.detail.deferred.resolve);
ev.detail.deferred.resolve(42);
} catch (e) {
console.error(e);
}
});
function runTest ($) {
// Test resolve directly.
$.Deferred(function (def) {
def.resolve(99);
}).then(function (v) {
console.log(`resolved: ${v}`);
});
// Test through event listener.
$.Deferred(function (def) {
window.dispatchEvent(new CustomEvent('test-event-1234', { detail: {
deferred: def
}}));
}).then(function (v) {
console.log(`resolved: ${v}`);
});
}
// Inject script into page and run it.
let script = document.createElement('script');
script.type = 'text/javascript';
script.textContent = `(${runTest.toString()})(window.jQuery)`;
document.body.appendChild(script);
值得注意的是:
document-idle
运行,因此jQuery已经可用。none
授权,以便进行沙盒处理。runTest
功能注入页面并从那里运行。 假设要做的是发送" test-event-1234"将ev.detail.deferred
设置为jQuery延迟对象,然后等待事件侦听器解析它。但是,它会在控制台中输出以下内容:
resolved: 99
Object { resolve: Deferred/</e[f[0]](), resolveWith: fireWith(),
reject: Deferred/</e[f[0]](), rejectWith: fireWith(),
notify: Deferred/</e[f[0]](), notifyWith: fireWith(),
state: state(), always: always(), then: then(),
promise: promise(), 4 more… }
undefined
TypeError: ev.detail.deferred.resolve is not a function
Stack trace:
// indicates the resolve() call in the event listener
&#34;已解决:99&#34;是直接(无事件监听器)测试的输出,表明此时确实存在resolve()
。
下一行输出是事件处理程序中的console.log(ev.detail.deferred)
,它显示resolve
在某个时刻存在(并且至少确认我将正确的对象传递给事件处理程序),但是console.log(ev.detailed.deferred.resolve)
(我在Kevin B's suggestion之后添加,以免被异步控制台输出问题误导)显示undefined
。
然后,呼叫失败,说明ev.detail.deferred.resolve
不是函数。
以下事项使这项工作正常:
@grant none
,以便它不会被沙箱化。这里发生了什么?我已经盯着这一段时间,我非常有信心没有任何错别字。我无法弄清楚为什么resolve
未定义,特别是考虑到&#34;直接&#34;在调用resolve
之前进行测试,没有任何问题。有没有办法使这项工作?
在(删除)评论中提出了一些测试。到目前为止,所有这些都产生与上述相同的结果:
创建延迟对象之前的延迟:
// Test with delay #1
window.setTimeout(function () {
$.Deferred(function (def) {
window.dispatchEvent(new CustomEvent('test-event-1234', { detail: {
deferred: def
}}));
}).then(function (v) {
console.log(`resolved: ${v}`);
});
}, 1000);
调度事件前的延迟:
// Test with delay #2
$.Deferred(function (def) {
window.setTimeout(function () {
window.dispatchEvent(new CustomEvent('test-event-1234', { detail: {
deferred: def
}}));
}, 2000);
}).then(function (v) {
console.log(`resolved: ${v}`);
});
在致电resolve
之前延迟事件:
// Event listener calls ev.detail.deferred.resolve() after a delay.
window.addEventListener('test-event-delayed-1234', function (ev) {
window.setTimeout(function () {
try {
console.log(ev.detail.deferred.resolve);
ev.detail.deferred.resolve(42);
} catch (e) {
console.error(e);
}
}, ev.detail.timeout);
});
... then, elswhere: ...
// Test with delay #3
$.Deferred(function (def) {
window.dispatchEvent(new CustomEvent('test-event-delayed-1234', { detail: {
deferred: def,
timeout: 3000
}}));
}).then(function (v) {
console.log(`resolved: ${v}`);
});