重新解析jquery.Deferred(或其他承诺)

时间:2014-03-25 12:33:58

标签: javascript jquery promise jquery-deferred

AFAIK Deferreds只能解决一次,但我有一个场景,我在表格中存储了很多Deferreds。这些延期可能会导致这种情况发生。值将需要更新其他模块将要存储对原始延迟的本地引用,因此我不能用新对象覆盖整个延迟。

我是否有某种方法可以覆盖延期价值,或者如果(我怀疑)它是不可取的(甚至是不可能的)是否有任何经过试验和测试的方法来解决这个问题?这里有一些框架代码来说明问题

// articles module
var articles = {},

// anId = 'uuid';

articles[anId] = $.get('/articles/' + anId);

//another module

var localCopyOfArticle,
    getArticle = function (anId) {
        localCopyOfArticle = articles[anId]
    }
getArticle('uuid');

// back to articles
articles[anId] = $.get('/articles/refresh/' + anId);

//another module again
console.log(localCopyOfArticle) // oh no - it's out of date

2 个答案:

答案 0 :(得分:2)

  

AFAIK Deferreds只能解决一次

正确。从待处理状态转换为已履行或已拒绝状态(也已解决)的承诺不再能够改变状态。承诺规范明确地说明了这一点:

  

当履行/拒绝时,承诺不得过渡到任何其他州。

所以,你有它,没有 - 承诺在解决后不会改变状态。就像返回值的函数一样,回想起来不会突然抛出异常。每当你不确定时 - 考虑同步代码类比

var x = foo(); // returns correctly
// .. more code

你不希望{<1}}在返回之后抛出,或者在投掷之后返回,就像你不希望承诺在解决后拒绝或在拒绝后解决。


  

我是否有某种方法可以覆盖延迟的价值,或者如果(我怀疑)它是不可取的(甚至不可能)是否有任何经过试验和测试的方法来解决这个问题?这是一些用于说明问题的框架代码

不,承诺是对单一计算的滥用。解决它两次是没有意义的。对你的目标来说,这似乎是错误的抽象。

Promise是一个很好的流量控制机制,但它们并不是要解决asnychronosu代码必须处理的每个问题。它们不是一个事件发射器。

然而,这个问题很容易通过承诺来解决:

foo

这段代码有很多“残酷”来说明这一点。重要的是要意识到操作每次都是一个新的操作。每次获取数据都是一项新操作,而不是同一项操作。就像在同步代码中一样。将值存储在映射中而不是promises中,并且fetch操作应该基于promise。

答案 1 :(得分:0)

而不是将deferred存储在articles模块中,您可以存储jquery Callbacks对象,并在ajax调用完成时触发它。这将允许您拥有多个订阅者,并允许您多次通知每个订阅者:

// articles module
var articles = {},

// anId = 'uuid';

// create jquery callbacks object.
articles[anId] = $.Callbacks();

// load the article and fire all callbacks that have been added to articles[anId]
$.get('/articles/' + anId)
    .then(function (data) { articles[anId].fire(data); });

// add a callback to articles[anId] whose purpose is to keep localCopyOfArticle up to date.
var localCopyOfArticle = null;
articles[anId].add(function(data) {
    localCopyOfArticle = data;
});

// back to articles
articles[anId] = $.get('/articles/refresh/' + anId)
    .then(function (data) { articles[anId].fire(data); });