AngularJS:链接承诺 [英] AngularJS : Chaining promises

查看:26
本文介绍了AngularJS:链接承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据 AngularJS 验证和承诺的建议,我想链接确认对话框和因此一次验证几个步骤.

Following the suggestions from AngularJS validation and promises, I would like to chain confirmation dialogs and thus validate several steps at once.

根据用户提供的数据,进行API调用,查看所有需要用户确认的内容.每一步需要确认,提示用户,让他们决定是否进行下一步.如果任何步骤返回 false,则整个链都应返回 false.

Based on data provided by the user, an API call is made to see what all needs to be confirmed by the user. For each step that needs confirmation, prompt the user and let them decide whether to go to next step. If any step returns false, the whole chain should return false.

我已经阅读了很多关于异步 JS 和 promises 的内容,但我不得不承认我对它仍然很陌生.如何正确链接这些以获得所有步骤的最终真/假?请注意,需要调用 API 来根据提供的信息确定需要向用户显示的所有内容,因此 fetchSomeData() 作为链中的第一个调用.

I've been reading a lot about async JS and promises, but I have to admit I am still fairly new to it. How to properly chain these to get a final true/false for all steps? Note that an API call is needed to determine what all needs to be shown to the user based on provided information, hence fetchSomeData() as first call in the chain.

任何帮助或建议将不胜感激.

Any help or suggestions will be greatly appreciated.

fetchSomeData = function() {
    var deferred = $q.defer();
    api.fetchData(param1, param2, param3)
        .then(function(data) {
        deferred.resolve(data.content);
    }, api.errorHandler);
    return deferred.promise;
}
// data = {condition1: false, condition2: true, condition3: true}
// display confirmation dialogs for step 2 and step 3, not step 1 

confirmStep1 = function(data) {
    if (data.condition1) {
        return confirmDialogService.popConfirm('step1').then(function(confirmed) {
            return confirmed;
        }, function() {
            return false;
        });
    } else {
        return $q.when(true);
    }
}

confirmStep2 = function(data) {
    if (data.condition2) {
        return confirmDialogService.popConfirm('step2').then(function(confirmed) {
            return confirmed;
        }, function() {
            return false;
        });
    } else {
        return $q.when(true);
    }
}

confirmStep3 = function(data) {
    if (data.condition3) {
        return confirmDialogService.popConfirm('step3').then(function(confirmed) {
            return confirmed;
        }, function() {
            return false;
        });
    } else {
        return $q.when(true);
    }
}

confirmSteps = function() {
    return fetchSomeData()
        .then(confirmStep1(data))
        .then(confirmStep2(data))
        .then(confirmStep3(data));
}

confirmSteps().then(function(allConfirmed) {
    if (allConfirmed == true) {
        doSomething();
    } else {
        return;
    }
});

推荐答案

dfsq 开始写一个答案,但在他的祝福下删除了他的所以我添加了我的看法:

dfsq started writing an answer but deleted his so with his blessing I'm adding my take on it:

confirmSteps = function() {
    return fetchSomeData()
        .then(confirmStep1(data))
        .then(confirmStep2(data))
        .then(confirmStep3(data));
}

这会调用函数,它与 setTimeout(alert("Hi"),5) 相同,您不想调用要链接它们的函数.像 setTimeout(function(){ alert("Hi"); }, 5);

This calls functions, it's the same as setTimeout(alert("Hi"),5) you don't want to be calling the functions you want to chain them. Like setTimeout(function(){ alert("Hi"); }, 5);

confirmSteps = function() {
    return fetchSomeData()
        .then(confirmStep1)
        .then(confirmStep2)
        .then(confirmStep3);
}

然而,这只会将 data 传递给第一个 promise,而将前一个 promise 的结果传递给下一个 promise,而您希望将 data 传递给所有三个,您可以通过设置一个级别来做到这一点:

However, that would pass data to the first promise only and the result of the previous promise to the next one, instead you want to pass data to all three, you can do this by neting one level:

confirmSteps = function() {
    return fetchSomeData().then(function(data){
        var v1, v2;
        return confirmStep1(data).then(function(d){ 
           v1 = d;
           return confirmStep2(data);
        }).then(function(d){
           v2 = d;
           return confirmStep3(data);
        }).then(function(v3){
            return v1 && v2 && v3;
        })
    });
};

这可行,但有点笨拙,您可以使用短路 - 有点像 && 仅在左侧评估为假时.此外,我们可以在一个中心位置进行所有错误处理.这将使您的代码看起来像.

This works but it's kind of crufty, instead you can use short circuiting - kind of like how && only evaluates the left hand side if it's falsey. Moreover we can do all error handling in a central location. This would make your code look like.

confirmStep1 = function(data) {
    if (data.condition1) return $q.when(true);
    return confirmDialogService.popConfirm('step1');
};

confirmStep2 = function(data) {
    if (data.condition2) return $q.when(true);
    return confirmDialogService.popConfirm('step2');
};

confirmStep3 = function(data) {
    if (data.condition3) return $q.when(true);
    return confirmDialogService.popConfirm('step3'):
};

confirmSteps = function() {
    var data = fetchSomeData();
    return data.then(confirmStep1).then(function(soFar){ 
         if(!soFar) return false; 
         return data.then(confirmStep2); 
    }).then(function(soFar){ 
         if(!soFar) return false; 
         return data.then(confirmStep3); 
    }).catch(function(){ return false; });
};

作为一个额外的提示:

fetchSomeData = function() {
    var deferred = $q.defer();
    api.fetchData(param1, param2, param3)
        .then(function(data) {
        deferred.resolve(data.content);
    }, api.errorHandler);
    return deferred.promise;
};

可以简单地变成:

fetchSomeData = function() {
    return api.fetchData(param1, param2, param3).then(function(data) {
        return data.content;
    }, api.errorHandler);
};

这篇关于AngularJS:链接承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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