javascript - 将 Deferred 添加到非异步函数

标签 javascript jquery asynchronous promise deferred

我目前正在开发一个需要很长时间才能完成的函数,因为我无法让它更快地完成,而且我要从其他脚本中调用它,我想知道是否有一种方法可以在该函数中使用类似 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 ( specificationMDN ),因此它根本不在主 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/

相关文章:

javascript - 当 div 过半时触发路径点

javascript - 我需要javascript吗?在 PHP 中?

javascript - 在同步回调函数中等待异步回调函数

python - 如何同时处理多个 websocket 消息?

javascript - 嵌套的异步调用似乎没有按预期执行

javascript - Javascript 中删除运算符的目的是什么?

javascript - 如果有 cookie,则隐藏代码

javascript - 音频排队未立即播放

c++ - 异步 cppcms session 。模式

javascript - 如果值不存在则隐藏追加元素