我目前正在开发一个需要很长时间才能完成的函数,因为我无法让它更快地完成,而且我要从其他脚本中调用它,我想知道是否有一种方法可以在该函数中使用类似 Promise 的东西。
基本上
function longrunning(){
var def = new $.Deferred();
var result = {};
[DO STUFF THAT TAKES A WHILE]
def.resolve();
return def.promise(result);
}
我的基本问题是,由于所有正在发生的事情都不是异步的,所以在一切完成之前我的 promise 不会被返回,因此稍后调用长时间运行的函数将不知道它是异步的。但当然,如果我在执行所有代码之前返回 promise ,它根本不会解决。我希望你能明白我想做的事。希望有人有想法。提前致谢,
问候克里斯
最佳答案
将代码包装在 $.Deferred
(或 native promise )中不会有任何帮助,即使您确实在执行长时间运行的工作之前设法将 promise 返回到调用代码(对于实例,通过setTimeout
)。它要做的就是让主 UI 线程在 稍后、在 longrunning
返回 promise 之后不久抢占,而不是在调用 longrunning
本身时。所以,没用。 :-)
如果相关函数不操作 DOM,或者它所做的操作可以与长时间运行的逻辑分开,那么这是一个很好的候选者,可以将其转移到网络 worker ( specification 、 MDN ),因此它根本不在主 UI 线程上运行,而是在并行工作线程中运行,从而使 UI 可以自由地继续响应。
longrunning
不会做实际的工作,它只是 postMessage
工作人员要求它做工作,然后在它返回时解决你的 promise 工作已完成的消息。沿着这些思路(这只是一个代码草图,而不是一个完全实现的解决方案):
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
[结果] 或 error
[错误]。)
如您所见,我们将 longrunning
将工作发送给工作人员并返回一个 promise ;当工作人员将工作发回时,监听器将解决延迟问题。
如果长时间运行的任务确实需要将 DOM 操作作为其工作的一部分,它可以将必要的信息发送回主脚本,以使其在必要时代表自己执行这些操作。其可行性自然取决于代码正在做什么。
<小时/>当然,如果您只需在最新的浏览器上运行(或包含填充),您可以使用 native Promise 而不是 jQuery 的 $.Deferred
:
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 work = pendingWork[e.data.id];
if (!work) {
console.error("Got result for work ID " + e.data.id + " but no pending entry for it was found.");
} else {
if (e.data.success) {
work.resolve(e.data.result);
} else {
work.reject(e.data.error);
}
delete pendingWork[e.data.id];
}
});
function longrunning(info) {
return new Promise(function(resolve, reject) {
// Get an identifier for this work
var id = ++workid;
pendingWork[id] = {resolve: resolve, reject: reject};
worker.postMessage({id: id, info: info});
});
}
关于javascript - 将 Deferred 添加到非异步函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42277143/