在下面的代码中,每当任何一个延迟对象失败时,我都需要退出for循环。每当循环大写red
或yellow
颜色失败并且我想避免其他延迟被执行。
var colours = ['violet', 'indigo', 'blue', 'green', 'yellow', 'orange', 'red'];
var capitalize = function(text) {
var deferred = $.Deferred(),
delay = (1 + Math.floor(Math.random() * 5)) * 500;
setTimeout(function() {
if (text === 'red' || text === 'yellow') {
deferred.reject('error colour', true);
} else {
deferred.resolve(text.toUpperCase());
}
}, delay);
return deferred.promise();
}
var deferreds = [],
result = [];
for (var i = 0; i < colours.length; i++) {
var deferred = capitalize(colours[i]);
deferred.done(function(t) {
console.log(t);
result.push(t);
}).fail(function(e) {
console.log(e);
});
deferreds.push(deferred);
}
$.when.apply($, deferreds).done(function(){
console.log(result);
}).fail(function(e){
console.log(e);
});
修改
我正在建立一个基于Cordova的移动应用程序,带有主干。我使用localStorage进行持久化,并且在持久化之前加密所有数据。虽然使用localstorage存储/检索数据是同步的,但是为了加密/解密数据,我调用异步的本机设备API。我想过使用Backbone.localstorage插件,但它不是为异步开发的......所以没那么有用!
我正在开发自己的插件。除了一种方法,findAll
之外,我几乎完成了大部分代码。
findAll
方法返回存储在localstorage中的所有模型。
// exiting method in the Backbone.Localstorage plugin
extend(Backbone.LocalStorage.prototype, {
// ...
findAll: function() {
var result = [];
for (var i = 0, id, data; i < this.records.length; i++) {
id = this.records[i];
data = this.serializer.deserialize(this.localStorage().getItem(this._itemName(id)));
if (data != null) result.push(data);
}
return result;
}
});
在localstorage中,所有模型都被加密并存储为字符串。在反序列化回模型之前,我已经解密了它们。 this.crypto
类解密从localstorage返回的字符串并反序列化回模型。加密/解密是aysnc,因此它返回一个promise。
// Method in my new plugin
findAll: function () {
var deferred = $.Deferred(),
deferreds = [],
result = [],
errors = [];
// this.records contains all the model ids
for (var i = 0, id, data; i < this.records.length; i++) {
id = this.records[i];
// this.crypto return a promise with the backbone model as parameter
var d = this.crypto.deserialize(this.localStorage().getItem(this._itemName(id)));
d.done(function(model) {
// I've to maintain the order in result so storing the index
result.push({ index: i, model: model });
}).fail(function(error) {
errors.push(error);
});
deferreds.push(d);
}
$.when.apply($, deferreds)
.done(function() {
// TODO: sort the result based on i and resolve it
deferred.resolve(sortedResult);
})
.fail(...);
return deferred.promise();
}
解密时可能会出现错误,在这种情况下,我可以停止整个过程。
答案 0 :(得分:1)
“只要......它失败了,我想避免其他延期执行”
暂时考虑一下。这是不可能的。
for
循环,用于创建和运行异步函数(即“延迟”)。 有几种可能的解决方案,但它们都依赖于更好的问题定义。
答案 1 :(得分:1)
您的新findAll
方法将简化如下:
findAll: function () {
var promises = this.records.map(function(record) {
return this.crypto.deserialize(this.localStorage().getItem(this._itemName(record)));
});
return $.when.apply(null, promises).then(function() {
return Array.prototype.slice.apply(arguments);//convert arguments to array
});
}
成功后,这将按照您想要的顺序返回一系列结果的承诺 - 无需对任何内容进行排序。任何单独的异步失败都将导致返回的承诺被拒绝。但是,这种拒绝为时已晚,无法阻止已经发出的其他异步调用。
为了允许无法禁止进一步调用this.crypto.deserialize(...)
,您必须以串行方式(以菊花链形式)执行调用,从而允许每次调用的结果确定下一步操作。< / p>
findAll: function () {
var results = [];
return this.records.reduce(function(promise, record) {
return promise.then(function(result) {
if(result) results.push(result);
return this.crypto.deserialize(this.localStorage().getItem(this._itemName(record)));
});
}, $.when()).then(function() {
return results;
});
}
和以前一样,成功后,这将按照您想要的顺序返回一系列结果的承诺。
由于每个阶段仅在前一阶段成功时执行,因此在异步失败时将自动禁止进一步调用。虽然.reduce(...)
无条件地建立了一个链条,但拒绝将迫使链条沿着其失败路径 - 失败的权利将被跳过(它们没有失败的处理程序)。
如果您需要根据测试result
强制失败,情况会略有不同,但整体模式基本相同。