我目前正在开发一项需要相当长时间才能完成的功能,因为我无法让它更快完成并且即将从其他脚本调用它我想知道是否存在是一种在该函数中使用类似promise的方法。
基本上
function longrunning(){
var def = new $.Deferred();
var result = {};
[DO STUFF THAT TAKES A WHILE]
def.resolve();
return def.promise(result);
}
我的基本问题是,由于所有正在发生的事情都不是异步,我的承诺在一切都完成之前都不会被回复,因此稍后调用longrunning的函数会赢得#t知道它是异步的。但是当然如果我在执行所有代码之前返回承诺,它根本不会解决。我希望你能得到我想做的事情。希望有人有个主意。提前致谢并
问候克里斯
答案 0 :(得分:1)
将代码包装在$.Deferred
(或原生承诺)中,即使您在执行长时间运行之前设法将承诺返回到调用代码,也无法提供帮助(例如,通过setTimeout
)。在longrunning
返回承诺后不久,主要的UI线程会在稍后中占用,而不是在调用longrunning
本身时。所以,没用。 : - )
如果有问题的函数没有操作DOM,或者它的操作可以与长期运行的逻辑分开,那么这是一个很好的候选者,可以转移到 web worker (specification,MDN),所以它根本不会在主UI线程上运行,而是在并行工作线程中运行,让UI自由继续回应。
longrunning
不会做实际的工作,它只会postMessage
工人要求它完成工作,然后在收到工作消息时解决你的承诺已经完成了。沿着这些方向的东西(这只是一个代码草图,而不是一个完全实现的解决方案):
var pendingWork = {};
var workId = 0;
var worker = new Worker("path/to/web/worker.js");
worker.addEventListener("message", function(e) {
// Worker has finished some work, resolve the Deferred
var d = pendingWork[e.data.id];
if (!d) {
console.error("Got result for work ID " + e.data.id + " but no pending entry for it was found.");
} else {
if (e.data.success) {
d.resolve(e.data.result);
} else {
d.reject(e.data.error);
}
delete pendingWork[e.data.id];
}
});
function longrunning(info) {
// Get an identifier for this work
var id = ++workid;
var d = pendingWork[id] = $.Deferred();
worker.postMessage({id: id, info: info});
return d.promise();
}
(假设工作人员发回的是具有属性id
[工作ID],success
[flag]和result
[结果]或{的对象{1}} [错误]。)
正如您所看到的,我们有error
将工作发送给工人并为其返回承诺;当工作人员发回工作时,监听器解析延迟。
如果长时间运行的任务 需要将DOM操作作为其工作的一部分,它可以将必要的信息发布回主脚本,以便在必要时代表它进行操作。这种可行性自然取决于代码的作用。
当然,如果你只需要在最新的浏览器(或包含polyfill)上运行,你可以使用本机承诺而不是jQuery的longrunning
:
$.Deferred