如何利用$ .Deferred()来处理回调函数和ajax调用

时间:2015-08-19 16:25:28

标签: javascript jquery ajax callback promise

我刚刚开始使用promises,我可以使用一些指导如何使这个场景工作。下面的代码来自一个更大的插件文件,但我刚刚包含了我认为相关的部分。

有一个回调函数(callbackBeforeSend),我将执行一些异步地理位置(我已经完成了这个工作)并且我需要保持ajax调用,直到这些函数完成。

我在代码中看到他们使用$ .Deferred()来处理ajax响应,我想知道是否有办法将回调函数和初始ajax调用绑定到$ .Deferred()以及处理所有事情的正确执行顺序。

所以我想要发生的是

  1. 回调功能触发
  2. 异步内容发生在回调中并返回lat,lng,address
  3. Ajax使用从回调
  4. 返回的lat,lng,地址触发

    非常感谢任何帮助。我仍然不太了解承诺,但我正在努力学习。谢谢!

    $.extend(Plugin.prototype, {
        _getData: function (lat, lng, address) {
            var _this = this;
            var d = $.Deferred();
    
            if (this.settings.callbackBeforeSend) {
                this.settings.callbackBeforeSend.call(this, lat, lng, address);
            }
    
            $.ajax({
                type         : 'GET',
                url          : this.settings.dataLocation + (this.settings.dataType === 'jsonp' ? (this.settings.dataLocation.match(/\?/) ? '&' : '?') + 'callback=?' : ''),
                // Passing the lat, lng, and address with the AJAX request so they can optionally be used by back-end languages
                data: {
                    'origLat' : lat,
                    'origLng' : lng,
                    'origAddress': address
                },
                dataType     : dataTypeRead,
                jsonpCallback: (this.settings.dataType === 'jsonp' ? this.settings.callbackJsonp : null)
            }).done(function (p) {
                d.resolve(p);
    
                // Loading remove
                if(_this.settings.loading === true){
                    $('.' + _this.settings.formContainer + ' .' + _this.settings.loadingContainer).remove();
                }
            }).fail(d.reject);
            return d.promise();
        }
    });
    

3 个答案:

答案 0 :(得分:0)

我真的不喜欢jQuery的承诺,但如果你必须......

function callBackBeforeSend(){
   var def = $.Deferred();
   //Async operation here:
   async(function(lat, lng, address) {
       //pass resolve an object with all information
       //the async callback function might not use 3 parameters, but an 
       //object containing all
       def.resolve({ lat : lat, lng : lng, address : address});
       //async function callback
    });
   return def.promise();
}

然后,您可以使用deferred.then()来获取已解析的数据。

var prom = callbackBeforeSend();
prom.then(function(obj){
    //lat, lng, address within obj
    //use on ajax call below.
    $.ajax();
});

然后,您可以使用then来链接方法 我还要查看你正在使用的jQuery版本。 jQuery 1.8之前的行为可能会有所不同。

这是使用ES6承诺:

function callbackBeforeSend(){
    return new Promise(function(resolve) {
         async(function(lat, lng, address){
             resolve({lat : lat, lng : lng, address : address});
         });
    });
}

那就是同样的事情:

var prom = callbackBeforeSend(); //firstRequest
prom.then(function(obj){
    //Callback finished
    //obj holds lat, lng, address
    //Do ajax request:
    $.ajax();
});

答案 1 :(得分:0)

  
      
  1. 回调功能触发
  2.   
  3. 异步内容发生在回调和返回中   lat,lng,地址
  4.   
  5. Ajax使用lat,lng,地址触发   从回调中返回
  6.   
$.when(callback())
.then(function(data) {
  // `data`: `lat` , `lng`, `address` ...
  var settings = {url:url, data:{...}, type:"GET"};
  return $.ajax(settings)
}, function(jqxhr, textStatus, errorThrown) {
  console.log(errorThrown);
  return errorThrown
})
.then(function(data) {
  // do stuff when `callback` , `$.ajax()` completes
}, function(err) {
  console.log(err);
});

答案 2 :(得分:0)

可能最重要的事情是:

  • 要求(可选)在执行ajax之前调用异步callbackBeforeSend(),要求Promise由callbackBeforeSend()返回或创建。
  • $.ajax()返回一个jqXHR对象,实际上是一个Promise,因此$.ajax()不需要您创建/解析自己的Deferred。

试试这个:

$.extend(Plugin.prototype, {
    _getData: function (lat, lng, address) {
        var settings = this.settings;
        var promise = settings.callbackBeforeSend ? $.when(settings.callbackBeforeSend.call(this, lat, lng, address)) : $.when();
        return promise.then(function() {
            return $.ajax({
                type: 'GET',
                url: settings.dataLocation + (settings.dataType === 'jsonp' ? (settings.dataLocation.match(/\?/) ? '&' : '?') + 'callback=?' : ''),
                data: { 'origLat':lat, 'origLng':lng, 'origAddress':address },
                dataType: dataTypeRead,
                jsonpCallback: (settings.dataType === 'jsonp' ? settings.callbackJsonp : null)
            });
        }).then(null, function(jqXHR, textStatus, errorThrown) {
            return errorThrown;
        });
    }
});

如果settings.callbackBeforeSend()已经返回了一个承诺,则可以免除$.when(...)包装。

你的" loading"指示应该(通过惯例)附加并随后在相同的代码块中删除 - 在_getData()内或在调用函数中。

例如,调用函数可能会调用._getData()并按如下方式对其结果进行操作:

var $spinner = $("#myLoadingElement").appendTo('.wherever');//pseudocode
foo._getData(lat, lng, address).then(function(data) {
    //do whatever on success
}, function(error) {
    //do whatever on error
}).always(function() {
    $spinner.remove();//remove the spinner regardless of the outcome.
});