如何使用deferred()依次触发JQuery函数?

时间:2015-08-25 18:49:17

标签: javascript jquery

我在jquery里面的deferred()方法周围遇到了麻烦。我花了几个小时阅读文档,但我仍然不完全理解我在做什么。

我的基本问题是,我有一系列函数(不是ajax调用),我想按顺序运行,但如果其中任何一个出错,请停止所有进程。

这是我已经走了多远(我已经删除了一堆不需要的代码,只是离开了基本想法)

//The module  var myModule = (function() {

//Defaults
var vOne;
var VTwo;
var deferred = $.Deferred();

//Private method
var _myPrivateFunction1 = function(userID) {
    if(userID >= 10) {
        //All is good, set var vOne to true and run next function
        vOne = true;
        return deferred.promise();
    } else {
        //User is not allowed, stop everything else and show the error message
        return deferred.reject();
    }
}

var _myPrivateFunction2 = function() {
    if(vOne === true) {
        //Ok we can keep going
        return deferred.promise();
    } else {
        //again stop everything and throw error
        return deferred.reject();
    }
};

var _myPrivateFunction3 = function(element) {
    //...and so on
};


var _errorMsgFunction = function(msg) {
    $.log("There was an error: " + msg);
    return false;
};


//Public method
var myPublicFunction = function(element,call) {
    //element is jquery object passed through user "click" event
    var userID = element.data('id')
    var userAction = element.data('action');

    //Now... i want to fire _myPrivateFunction1, _myPrivateFunction2, _myPrivateFunction3 in sequence and STOP all processes, and run 
    // _errorMsgFunction if there is an error in any of them.
    //This is how far I've gotten...

    _myPrivateFunction1(userID).then(_myPrivateFunction2(userAction), _errorMsgFunction("Error in _myPrivateFunction2")).then(_myPrivateFunction3(element),_errorMsgFunction("Error in _myPrivateFunction3")).fail(_errorMsgFunction("Error in _myPrivateFunction1"));

};

// Public API
return {
    myPublicFunction: myPublicFunction
};
})();

所以现在我一直得到“_myPrivateFunction2中的错误”(我为了测试目的而强迫这个错误),但是继续开火之后的其他功能......他们不会停止。我在这里缺少什么?

2 个答案:

答案 0 :(得分:2)

您无法共享延迟对象。您应该为每个函数的延迟创建一个不同的promise。

这是一个非常简单的例子,为了简单起见使用sycnhronus函数,尽管promises旨在与异步函数一起使用:

var func1 = function(arg){
    var dfd = jQuery.Deferred();
    if (arg === 0) {
        dfd.resolve('func1 Ok');
    } else {
        dfd.reject('func1 arg != 0');
    }
    return dfd.promise();
}

var func2 = function(arg){
    var dfd = jQuery.Deferred();
    if (arg === 0) {
        dfd.resolve('func2 Ok');
    } else {
        dfd.reject('func2 arg != 0');
    }
    return dfd.promise();
}

var func3 = function(arg){
    var dfd = jQuery.Deferred();
    if (arg === 0) {
        dfd.resolve('func3 Ok');
    } else {
        dfd.reject('func3 arg != 0');
    }
    return dfd.promise();
}

如果函数不依赖于其他函数进行处理,我们可以使用jQuery.when

并行执行
// Parallel processing

jQuery.when(func1(1), func2(0), func3(0)).then(function(res1, res2, res3){
    console.log(res1, res2, res3);
}).fail(function(reason){
    console.error(reason); // will fail with reason func1 arg != 0
});

如果是序列处理(因为我认为你的问题是),你应该这样做:

// Sequential processing

func1(0).then(function(res1){
    return func2(res1);
}).then(function(res2){
    return func3(res2);
}).then(function(res3){
    // everything ran ok, so do what you have to do...
}).fail(function(reason){
    console.log(reason);
});

上面的代码会失败,原因是:

> func2 arg != 0

如果你要进行混合并行和顺序处理,那么你应该混合两种方法。

声明

在我的例子中,如果func1func2有副作用,它们将不会在fail()内自行撤消。

最佳做法是在您完全确定一切正常时,即在最后then()次来电时,只有副作用。

答案 1 :(得分:1)

您需要在每个函数中单独使用$.deferred(),因为您希望为每个函数返回唯一的承诺。

//Private method
var _myPrivateFunction1 = function(userID) {
    var deferred = $.Deferred();
    if(userID >= 10) {
        //All is good, set var vOne to true and run next function
        vOne = true;
        deferred.resolve();
    } else {
        //User is not allowed, stop everything else and show the error message
        deferred.reject();
    }
    return deferred.promise();
}

然后你的公共职能应该有效。