【问题标题】:Looking for pattern to chain AJAX calls寻找链接 AJAX 调用的模式
【发布时间】:2014-09-10 13:31:32
【问题描述】:

我们有一个 AJAX Web 应用程序,我们有一个常见的模式是多个 ajax 调用一个接一个地调用。当我们保存带有多个附加实体的东西时,这很常见。一个例子可能是 saveCustomer() --> saveCustomerAddress() --> saveCustomersOrder()

我们目前有这样当methodA() 成功时,即第一个方法,它调用methodB(),等等(见下面的代码)。这种模式的缺点是很难看到发生了什么。如果您阅读 methodA(),您不会从方法名称中了解到它还调用了 methodB()methodC()。另一个缺点是,如果你想改变链接,你必须重写很多代码,如果你只想单独调用一个方法,那是做不到的,因为它会调用下游的方法。

function Tester() {
    this.url = 'https://public.opencpu.org/ocpu/library/';

    this.save = function() {
        this.methodA();
    }

    this.methodA = function () {
        var self = this;

        $.ajax({
            url: self.url,
            async: true
        }).always(function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {

            //check for errors... and if OK
            alert('A OK');
            self.methodB();

        })
    }
    this.methodB = function () {
        var self = this;

        $.ajax({
            url: self.url,
            async: true
        }).always(function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {

            //check for errors... and if OK
            alert('B OK');
            self.methodC();

        })
    }
    this.methodC = function () {
        var self = this;

        $.ajax({
            url: self.url,
            async: true
        }).always(function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {
            //OK
            alert('C OK');
        })
    }
}
new Tester().save();

我正在挠头,试图找出更好的模式。我想你可以将后面的方法封装在回调函数中,然后以某种方式将它们传递给每个方法,但我不确定如何处理。

是否有人知道在链接方法时可以删除方法依赖项的常见模式类型?

【问题讨论】:

标签: javascript ajax design-patterns


【解决方案1】:
function A() {
    writeMessage("Calling Function A");
    return $.ajax({
        url: "/scripts/S9/1.json",
        type: "GET",                    
        dataType: "json"
    });
}


function B(resultFromA) {
    writeMessage("In Function B. Result From A = " + resultFromA.data);
    return $.ajax({
        url: "/scripts/S9/2.json",
        type: "GET",
        dataType: "json"
    });
}


function C(resultFromB) {
    writeMessage("In Function C. Result From B =  " + resultFromB.data);
    return $.ajax({
        url: "/scripts/S9/3.json",
        type: "GET",
        dataType: "json"
    });
}

function D(resultFromC) {
    writeMessage("In Function D. Result From C = " + resultFromC.data);
}

A().then(B).then(C).then(D);

function writeMessage(msg) {
    $("#para").append(msg + "</br>");                 
}

【讨论】:

  • 这与其他答案有何不同?您只是从 ajax 调用中返回,对吗?那么这会阻止它异步吗?
  • jQuery Doc:Callbacks 按照它们添加的顺序执行。由于 deferred.then 返回一个 Promise,Promise 对象的其他方法可以链接到这个,包括附加的 .then() 方法。这就是我们在这里所做的。 jQuery 的每个 Ajax 方法都已经返回了一个 Promise。当函数 A 中的 Ajax 调用完成时,它会解析 promise。然后调用函数 B(),并将 Ajax 调用的结果作为其第一个参数。当 B() 中的 ajax 调用完成时,它会解析 Promise,并使用该调用的结果调用函数 C(),依此类推。
  • 知道了。我在这里更改了代码以适应他的解决方案:jsfiddle.net/h8tfrvy4/2
【解决方案2】:

你可以像这样使用动态调用:

        this.reqChain = ['req_1', 'req_2'];

        this.callChain = function(){
            if(!self.reqChain.length) return;
            ajax({
                url: self.reqChain[0],
                async: true,        
                always: function(processedDataOrXHRWrapper, textStatus, whrWrapperOrErrorThrown){
                   self.reqChain.shift();
                   $(document).trigger('request_'+self.reqChain[0]+'_callback', [processedDataOrXHRWrapper, textStatus, whrWrapperOrErrorThrown])
                   self.callChain();
                }
           });
    }

您可以传递回调,也可以绑定到动态事件。

【讨论】:

    【解决方案3】:

    这是我对自己问题的回答。我将我所有的方法包装在函数中,并通过回调传递给我的方法。

    它似乎完成了这项工作。有人有cmet吗?

    function Tester2() {
    
        this.save = function() {
    
            var self = this;
    
            var callbackC = function() {
                self.methodC();
            }
    
            var callbackB = function() {
                self.methodB(callbackC);
            }
    
            this.methodA(callbackB);
    
        }
    
        this.methodA = function (callbackFn) {
            var self = this;
    
            $.ajax({
                url: self.url,
                async: true
            }).always(function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {
    
    
                //check for errors... and if OK
                alert('A OK');
                if (callbackFn)
                    callbackFn();
    
            })
        }
        this.methodB = function (callbackFn) {
            var self = this;
    
            $.ajax({
                url: self.url,
                async: true
            }).always(function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {
    
    
                //check for errors... and if OK
                alert('B OK');
                if (callbackFn)
                    callbackFn();
    
            })
        }
        this.methodC = function () {
            var self = this;
    
            $.ajax({
                url: self.url,
                async: true
            }).always(function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {
                //OK
                alert('C OK');
            })
        }
    }
    
    new Tester2().save();
    

    【讨论】:

    • 是的,这完全没问题(我的意思是我的评论“或者,不太高级,只使用回调......”) - 除了 .always 忽略错误。如果您更习惯于回调而不是承诺,这可能更容易理解。 @Rotka 接受的答案更简洁,承诺被认为更优雅。
    【解决方案4】:

    试试这个:

    function Tester() {
        var self = this;
        this.url = 'https://public.opencpu.org/ocpu/library/';
    
        this.save = function() {
            self.methodA().then( self.methodB() ).then( self.methodC() )
        }
    
        this.methodA = function () {
            var self = this;
    
            return $.ajax({
                url: self.url,
                async: true
            }).always(function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {
    
                //check for errors... and if OK
                alert('A OK');
    
    
            })
        }
        this.methodB = function () {
            var self = this;
    
            return $.ajax({
                url: self.url,
                async: true
            }).always(function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {
    
                //check for errors... and if OK
                alert('B OK');
    
    
            })
        }
        this.methodC = function () {
            var self = this;
    
            return $.ajax({
                url: self.url,
                async: true
            }).always(function (processedDataOrXHRWrapper, textStatus, xhrWrapperOrErrorThrown) {
                //OK
    
            })
        }
    }
    new Tester().save();
    

    【讨论】:

    • 详细说明:这是使用 Promises,它内置于 jQuery 的 Ajax 实现中。更多信息可以在 jQuery 文档中找到。
    • 但是它用错了。您需要将回调传递给.then()!
    • 我不知道为什么有人给你投了反对票。这似乎工作正常。
    • 不,它没有。它并行执行所有三个 ajax 请求,这与您想要的顺序执行相反。
    • 哦,是的,对不起。在他的示例中,他正在执行该方法...即在传递给 then() 方法时使用 (),而在另一个答案中,只有方法 REFERENCE 被传递给 phew
    猜你喜欢
    • 2011-07-23
    • 1970-01-01
    • 2017-08-17
    • 2022-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-29
    • 1970-01-01
    相关资源
    最近更新 更多