使用promises实现回退 [英] Implementing a fallback using promises

查看:59
本文介绍了使用promises实现回退的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一种常见的模式,我们在数据源列表中级联,第一次成功打破了这样的链:

it is a common pattern that we cascade across a list of sources of data with the first success breaking the chain like this:

var data = getData1();
if (!data) data = getData2();
if (!data) data = getData3();

等等。如果 getDataN()函数是异步的,它会导致我们'回调地狱':

et cetera. if the getDataN() functions are asynchronous, however, it leads us to 'callback hell':

var data;
getData1(function() {
    getData2(function () {
        getData3(function () { alert('not found'); })
    })
});

其中的实现可能类似于:

where the implementations may look something like:

function getData1(callback) {
    $.ajax({
        url: '/my/url/1/',
        success: function(ret) { data = ret },
        error: callback
    });
 }

...我希望写下这样的承诺:

...with promises I would expect to write something like this:

$.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 的返回值,它本身就是一个承诺,我理解它是作为后续链步骤的输入链接的。

where the second .then actually refers to the return value of the first .fail, which is itself a promise, and which I understood was chained in as the input to the succeeding chain step.

显然我错了,但写这个的正确方法是什么?

clearly I'm wrong but what is the correct way to write this?

推荐答案

In大多数承诺库,您可以链接 .fail() .catch(),如@ mido22的回答,但是jQuery的 .fail()不会处理错误。保证始终传递输入承诺(具有未更改状态),如果/成功发生,则不允许级联所需的中断。

In most promise libs, you could chain .fail() or .catch() as in @mido22's answer, but jQuery's .fail() doesn't "handle" an error as such. It is guaranteed always to pass on the input promise (with unaltered state), which would not allow the required "break" of the cascade if/when success happens.

只有可以返回具有不同状态(或不同值/原因)的承诺的jQuery Promise方法是 .then()

The only jQuery Promise method that can return a promise with a different state (or different value/reason) is .then().

因此,您可以通过在每个阶段指定下一步作为当时的错误处理程序来编写一个继续出错的链。

Therefore you could write a chain which continues on error by specifying the next step as a then's error handler at each stage.

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()

But in practice, you might more typically create an array of functions or data objects which are invoked in turn with the help of Array method .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');
});

或者,这可能是一个更好的解决方案:

Or, as is probably a better solution here :

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');
});

这篇关于使用promises实现回退的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆