这是一个常见的模式,我们在数据源列表中进行级联,第一次成功打破了这样的链条。
var data = getData1();
if (!data) data = getData2();
if (!data) data = getData3();
等等,如果 getDataN() 函数是异步的,然而,它将我们引向 "回调地狱"。
var data;
getData1(function() {
getData2(function () {
getData3(function () { alert('not found'); })
})
});
在这里的实现可能看起来像..:
function getData1(callback) {
$.ajax({
url: '/my/url/1/',
success: function(ret) { data = ret },
error: callback
});
}
...对于承诺,我希望写出这样的东西:
$.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; });
其中第二个 .then
实际上指的是第一个 .fail
,这本身就是一个承诺,我的理解是,它是作为后续链步的输入而链入的。
显然我错了,但正确的写法是什么?
在大多数承诺类库中,你可以用链子 .fail()
或 .catch()
如同@mido22的答案,但jQuery的 .fail()
并不 "处理 "错误。它保证总是传递输入的promise(状态不变),如果成功的话,就不允许级联的 "中断"。
唯一的jQuery Promise方法,可以返回一个不同状态(或不同的valuereason)的承诺是 .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');
});
但在实践中,你可能会更典型地创建一个函数或数据对象的数组,这些函数或数据对象在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');
});
或者,这里可能是一个更好的解决方案。
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');
});
作为一个初学者,偶然发现了同样的问题,我才意识到有了这个问题,变得简单多了。async
和 await
:
同步模式
var data = getData1(); if (!data) data = getData2(); if (!data) data = getData3();
现在可以轻松地应用于异步代码。
let data = await getData1();
if (!data) data = await getData2();
if (!data) data = await getData3();
只要记得在代码中添加一个 async
到这个代码所使用的函数。