如何顺序运行多个函数,并在任何函数失败时停止所有函数?

时间:2017-10-14 02:37:51

标签: javascript jquery promise deferred sequential

我有多个Javascript函数,每个函数都执行一些DOM操作,然后运行ajax请求。我希望能够运行第一个函数,它操纵DOM然后触发它的ajax请求,然后,当ajax请求完成时,我想运行第二个函数,如果ajax请求返回true,或者停止执行其余的的函数和一些其他DOM操作(如显示错误消息)。

我希望这些函数一个接一个地顺序运行,并且只有在它们的ajax请求都没有返回false时才继续运行。如果它们都没有返回false,那么所有它们都应该运行,最后我会在“always”回调中进行一些操作。

我该如何做到这一点?

我的第一个想法是使用promises,以保持代码清洁,但经过几个小时的阅读后,我无法知道如何使这项工作。

下面是我当前的代码,这是我执行时在控制台中获得的代码:

inside test1
inside test2
inside test3
fail
[arguments variable from fail method]
always
[arguments variable from always method]

这是我想要在我的控制台中获取的内容(请注意缺少“inside test3”字符串):

inside test1
inside test2
fail
[arguments variable from fail method]
always
[arguments variable from always method]

以下是代码:

(function($) {
    var tasks = {
        init: function() {
            $.when(
                this.test1(),
                this.test2(),
                this.test3()
            ).done(function() {
                console.log('done');
                console.log(arguments);
            })
            .fail(function() {
                console.log('fail');
                console.log(arguments);
            })
            .always(function() {
                console.log('always');
                console.log(arguments);
            });
        },

        test1: function() {
            console.log('inside test1');
            return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler');
        },

        test2: function() {
            console.log('inside test2');
            // note the misspelled "typ" arg to make it fail and stop execution of test3()
            return $.getJSON('https://baconipsum.com/api/?typ=meat-and-filler');
        },

        test3: function() {
            console.log('inside test3');
            return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler');
        }
    };

    tasks.init();
})(jQuery)

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

我不熟悉jquery承诺。

但这应该有用

(function ($) {
    var tasks = {
        init: function () {
            this.test1().done(this.test2).done(this.test3)
                .done(function () {
                    console.log('done');
                    console.log(arguments);
                })
                .fail(function () {
                    console.log('fail');
                    console.log(arguments);
                })
                .always(function () {
                    console.log('always');
                    console.log(arguments);
                });
        },

        test1: function () {
            console.log('inside test1');
            return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler');
        },

        test2: function () {
            console.log('inside test2');
            // note the misspelled "typ" arg to make it fail and stop execution of test3()
            return $.getJSON('https://baconipsum.com/api/?typ=meat-and-filler');
        },

        test3: function () {
            console.log('inside test3');
            return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler');
        }
    };

    tasks.init();
})(jQuery)

答案 1 :(得分:1)

使用promises确实使代码更加清晰

注意:Promise / A + promise .then和.catch回调只接受一个参数,所以不需要查看arguments,只需使用一个参数

此代码(ES2015 +)显示了如何轻松

let p = Promise.resolve();
Promise.all([this.test1, this.test2, this.test3].map(fn => p = p.then(fn()))).then(allResults =>

或者,使用array.reduce

[this.fn1, this.fn2, this.fn3].reduce((promise, fn) => promise.then(results => fn().then(result => results.concat(result))), Promise.resolve([])).then(allResults =>

在这两种情况下,allResults都是来自testN函数的(已解析)结果数组

它创造了一个(已解决的)承诺,以“开始”承诺链

Array#map链接每个函数(this.test1等),然后在之前的结果中执行.then。每个this.testn promise的结果都在一个新数组中返回,该数组是Promise.all的参数

如果testN中的任何一个失败,则下一个不会被执行

var tasks = {
    init () {
        let p = Promise.resolve();
        Promise.all([this.test1, this.test2, this.test3].map(fn => p = p.then(fn())))
        .then(results => {
            console.log('done');
            console.log(results);
            return results; // pass results to next .then
        }).catch(reason => {
            console.log('fail');
            console.log(reason);
            return reason; // because I return rather than throw (or return a Promise.reject), 
            //the next .then can will get `reason` in it's argument
        }).then(result => {
            console.log('always');
            console.log(result);
        });
    },
    test1() {
        return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler');
    },
    test2() {
        return $.getJSON('https://baconipsum.com/api/?typ=meat-and-filler');
    },
    test3() {
        return $.getJSON('https://baconipsum.com/api/?type=meat-and-filler').then(result => {
            if(someCondition) {
                throw new Error("sum ting wong");
                // or
                return Promise.reject(new Error("sum ting wong"));
            }
            return result;
        });
    }
};
tasks.init();

对于问题中的代码,您可以进一步简化

var tasks = {
    init () {
        let p = Promise.resolve();
        const urls = [
            'https://baconipsum.com/api/?type=meat-and-filler',
            'https://baconipsum.com/api/?typ=meat-and-filler',
            'https://baconipsum.com/api/?type=meat-and-filler'
        ];
        Promise.all(urls.map(url => p = p.then(() => $.getJSON(url))))
        .then(results => {
            console.log('done');
            console.log(results);
            return results; // pass results to next .then
        }).catch(reason => {
            console.log('fail');
            console.log(reason);
            return reason; // because I return rather than throw (or return a Promise.reject), 
            //the next .then can will get `reason` in it's argument
        }).then(result => {
            console.log('always');
            console.log(result);
        });
    }
};
tasks.init();

答案 2 :(得分:0)

你不需要使用承诺 - 也许你知道这一点,但你可以继续在prevoius的成功块中调用下一个ajax请求,如下所示:

(function($) {
    var tasks = {
        init: function() {
                    $.post(url_1, data_1, function(data,status){
            if(status == 'success')
            {
                $.post(url_2, data_2, function(data,status){
                    if(status == 'success')
                    {
                        // ... and the next Ajax request goes here, etc.
                    }
                    else {
                        // show error message if 2nd Ajax request fails
                    }
                }
            else {
                // show error message if 1st Ajax request failes
            }
        });
    });    
        }

    tasks.init();
})(jQuery)