ekk*_*kis 6 javascript jquery promise jquery-deferred
这是一种常见的模式,我们在数据源列表中级联,第一次成功打破了这样的链:
var data = getData1();
if (!data) data = getData2();
if (!data) data = getData3();
Run Code Online (Sandbox Code Playgroud)
等等.但是,如果getDataN()函数是异步的,它会导致我们'回调地狱':
var data;
getData1(function() {
getData2(function () {
getData3(function () { alert('not found'); })
})
});
Run Code Online (Sandbox Code Playgroud)
实现可能看起来像这样:
function getData1(callback) {
$.ajax({
url: '/my/url/1/',
success: function(ret) { data = ret },
error: callback
});
}
Run Code Online (Sandbox Code Playgroud)
...有了承诺,我希望写下这样的东西:
$.when(getData1())
.then(function (x) { data = x; })
.fail(function () { return getData2(); })
.then(function (x) { data = x; })
.fail(function () { return getData3(); })
.then(function (x) { data = x; });
Run Code Online (Sandbox Code Playgroud)
其中第二个.then实际上是指第一个的返回值.fail,它本身就是一个承诺,我理解它被链接作为后续链步骤的输入.
显然我错了,但写这个的正确方法是什么?
Roa*_*888 11
在大多数承诺库中,您可以链接.fail()或.catch()在@ mido22的答案中,但jQuery .fail()不会"处理"错误.保证始终传递输入承诺(具有未更改状态),如果/成功发生,则不允许级联所需的"中断".
唯一可以返回具有不同状态(或不同值/原因)的promise的jQuery Promise方法是.then().
因此,您可以通过在每个阶段将下一步指定为then的错误处理程序来编写一个继续出错的链.
function getDataUntilAsyncSuccess() {
return $.Deferred().reject()
.then(null, getData1)
.then(null, getData2)
.then(null, getData3);
}
//The nulls ensure that success at any stage will pass straight through to the first non-null success handler.
getDataUntilAsyncSuccess().then(function (x) {
//"success" data is available here as `x`
}, function (err) {
console.log('not found');
});
Run Code Online (Sandbox Code Playgroud)
但实际上,您通常可以创建一个函数数组或数据对象,这些函数或数据对象在Array方法的帮助下依次调用.reduce().
例如 :
var fns = [
getData1,
getData2,
getData3,
getData4,
getData5
];
function getDataUntilAsyncSuccess(data) {
return data.reduce(function(promise, fn) {
return promise.then(null, fn);
}, $.Deferred().reject());// a rejected promise to get the chain started
}
getDataUntilAsyncSuccess(fns).then(function (x) {
//"success" data is available here as `x`
}, function (err) {
console.log('not found');
});
Run Code Online (Sandbox Code Playgroud)
或者,这可能是一个更好的解决方案:
var urls = [
'/path/1/',
'/path/2/',
'/path/3/',
'/path/4/',
'/path/5/'
];
function getDataUntilAsyncSuccess(data) {
return data.reduce(function(promise, url) {
return promise.then(null, function() {
return getData(url);// call a generalised `getData()` function that accepts a URL.
});
}, $.Deferred().reject());// a rejected promise to get the chain started
}
getDataUntilAsyncSuccess(urls).then(function (x) {
//"success" data is available here as `x`
}, function (err) {
console.log('not found');
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1279 次 |
| 最近记录: |