通用AJAX函数回调未按预期工作

时间:2015-02-18 13:31:47

标签: javascript jquery ajax

我创建了通用的ajax函数来使用REST API。

我已经编写了下面的代码,它一次正常工作一次。但如果我进行两次不同的呼叫,那么我的成功回调将覆盖最近的回调。

var ajax = {
    parameters: {
        url: '',
        dataType: 'json',
        data: {},
        contentType: 'application/json',
        loading: false,
        crossDomain: true,
        async: true,
        timeout: 30000,
        otherData: {}
    },
    callback: {
        success: null,
        error: null
    },
    get: function () {
        this.send('GET');
    },
    post: function () {
        this.send('POST');
    },
    del: function () {
        this.send('DELETE');
    },
    send: function (type) {
        self = this;
        if (!navigator.userAgent.match(/iPad|iPhone|iPod|android|blackberry|IEMobile/i)) {
            this.loadingIcon.show();

            if (this.isUndefined(this.parameters.dataType)) this.parameters.dataType = 'json';
            if (this.isUndefined(this.parameters.contentType)) this.parameters.contentType = 'application/json';
            if (this.isUndefined(this.parameters.loading)) this.parameters.loading = false;
            if (this.isUndefined(this.parameters.crossDomain)) this.parameters.crossDomain = true;
            if (this.isUndefined(this.parameters.async)) this.parameters.async = true;
            if (this.isUndefined(this.parameters.timeout)) this.parameters.timeout = 30000;
            if (this.isUndefined(this.callback.error)) this.callback.error = this.defaultError;

            return $.ajax({
                type: type,
                url: this.parameters.url,
                dataType: this.parameters.dataType,
                data: JSON.stringify(this.parameters.data),
                contentType: this.parameters.contentType,
                crossDomain: this.parameters.crossDomain,
                async: this.parameters.async,
                timeout: this.parameters.timeout,
                success: function (data) {
                    var args = arguments[2];
                    if (!self.isUndefined(self.callback.success)) {
                        if (self.isUndefined(self.parameters.otherData))
                            self.callback.success.call(this, data, args.statusText, args);
                        else
                            self.callback.success.call(this, data, args.statusText, args, self.parameters.otherData);
                    }
                    self.loadingIcon.hide();
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    xhrServerObj = xhr;
                    self.callback.error.call(xhr, ajaxOptions, thrownError);
                    self.loadingIcon.hide();
                }
            });
        }
    },
    isUndefined: function (param) {
        return (typeof param == 'undefined' || param == null);
    },
    defaultError: function (data, textStatus, jqXHR) {
    },
    loadingIcon: {
        show: function () {
            if (self.parameters.loading) {
                console.log('Show loading....');
            }
        },
        hide: function () {
            if (self.parameters.loading) {
                console.log('Hide loading....');
            }
        }
    }
}

我正在使用下面的

进行ajax调用
getAllStores(); 
getAllCategory();

function getAllStores() {
    var req = Object.create(ajax);
    req.parameters = { url: API + '/api/mobileapp/stores' };
    req.callback.success = successGetAllStores;
    req.get();
}
function successGetAllStores(data) {
    $.each(data, function (idx, d) {
        $("#StoreId").append($("<option value='" + d.StoreId + "'>" + d.StoreName + "</option>"));
    });
}

function getAllCategory() {
    var req = Object.create(ajax);
    req.parameters = { url: API + '/api/mobileapp/categories' };
    req.callback.success = successGetAllCategory;
    req.get();
}
function successGetAllCategory(data) {
    $.each(data, function (idx, d) {
        $("#CategoryId").append($("<option value='" + d.CategoryId + "'>" + d.CategoryName + "</option>"));
    });
}

如果我一次只调用一个函数 getAllStores(); ,那么在成功回调时我再次调用 getAllCategory()然后这个工作正常。不覆盖现有的回调函数。

您能否帮我解决如何使用通用ajax调用来处理多个呼叫以处理单个回调。

此外我尝试使用以下但仍然覆盖了最新的回调。

function MyAjax() {
    this.parameters = {
        url: '',
        dataType: 'json',
        data: {},
        contentType: 'application/json',
        loading: false,
        crossDomain: true,
        async: true,
        timeout: 30000,
        otherData: {}
    };
    this.callback = {
        success: null,
        error: null
    };
    this.get = function () {
        this.send('GET');
    };
    this.post = function () {
        this.send('POST');
    };
    this.del = function () {
        this.send('DELETE');
    };
    this.isUndefined = function (param) {
        return (typeof param == 'undefined' || param == null);
    };
    this.defaultError = function (data, textStatus, jqXHR) {
    };
    this.loadingIcon = {
        show: function () {
            if (self.parameters.loading) {
                console.log('Show loading....');
            }
        },
        hide: function () {
            if (self.parameters.loading) {
                console.log('Hide loading....');
            }
        }
    };
    this.send = function (type) {
        self = this;
        if (!navigator.userAgent.match(/iPad|iPhone|iPod|android|blackberry|IEMobile/i)) {
            this.loadingIcon.show();

            if (this.isUndefined(this.parameters.dataType)) this.parameters.dataType = 'json';
            if (this.isUndefined(this.parameters.contentType)) this.parameters.contentType = 'application/json';
            if (this.isUndefined(this.parameters.loading)) this.parameters.loading = false;
            if (this.isUndefined(this.parameters.crossDomain)) this.parameters.crossDomain = true;
            if (this.isUndefined(this.parameters.async)) this.parameters.async = true;
            if (this.isUndefined(this.parameters.timeout)) this.parameters.timeout = 30000;
            if (this.isUndefined(this.callback.error)) this.callback.error = this.defaultError;

            return $.ajax({
                type: type,
                url: this.parameters.url,
                dataType: this.parameters.dataType,
                data: JSON.stringify(this.parameters.data),
                contentType: this.parameters.contentType,
                crossDomain: this.parameters.crossDomain,
                async: this.parameters.async,
                timeout: this.parameters.timeout,
                success: function (data) {
                    var args = arguments[2];
                    if (!self.isUndefined(self.callback.success)) {
                        if (self.isUndefined(self.parameters.otherData))
                            self.callback.success.call(this, data, args.statusText, args);
                        else
                            self.callback.success.call(this, data, args.statusText, args, self.parameters.otherData);
                    }
                    self.loadingIcon.hide();
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    xhrServerObj = xhr;
                    self.callback.error.call(xhr, ajaxOptions, thrownError);
                    self.loadingIcon.hide();
                }
            });
        }
    }
}

使用下面的电话

var aj1 = new MyAjax();
    aj1.parameters = { url: API + '/api/mobileapp/stores' };
    aj1.callback.success = successGetAllStores;
    aj1.get();

    var aj2 = new MyAjax();
    aj2.parameters = { url: API + '/api/mobileapp/categories' };
    aj2.callback.success = successGetAllCategory;
    aj2.get();

2 个答案:

答案 0 :(得分:0)

认为我可以看到你的问题是什么 - 你使用相同的对象实例(ajax)作为每次调用object.create的原型(所以他们使用共享资源) - 所以后续调用它事物彼此踩得很厉害。

执行object.create时,您可以尝试使用$ .extend:

var clonedAjax = $.extend(true, {}, ajax);
var req = Object.create(clonedAjax);

但是 - 更简洁的方法是使用ajax作为类,而不是使用object.create。

function ajax(){
    this.parameters = {
        ....
    };
    this.get = function(){};
    .....
}

然后

var req = new ajax();

更新: GOT IT WORKING:它的外观是一个范围问题,这是你的方法的一个CUT DOWN工作示例 - 关键是你发送和使用时“scb”的分配在“成功”期间。 如果这不值得绿色勾选,那么什么都没有;)

var ajax = {
    parameters: {
        url: '',
        dataType: 'json',
        data: {},
        contentType: 'application/json',
        loading: false,
        crossDomain: true,
        async: true,
        timeout: 30000,
        otherData: {}
    },
    callback: {
        success: null,
        error: null
    },
    get: function ()
    {
        this.send('GET');
    },
    post: function ()
    {
        this.send('POST');
    },
    del: function ()
    {
        this.send('DELETE');
    },
    send: function (type)
    {
        self = this;
        if (!navigator.userAgent.match(/iPad|iPhone|iPod|android|blackberry|IEMobile/i))
        {

            var scb = self.callback.success; // at the point where you SEND, make a note of the callback's that are attached and use during success
            //note - the callbacks that are attached when the send succeeds / fails can be different!


            return $.ajax({
                type: type,
                url: this.parameters.url,
                dataType: this.parameters.dataType,
                data: JSON.stringify(this.parameters.data),
                contentType: this.parameters.contentType,
                crossDomain: this.parameters.crossDomain,
                async: this.parameters.async,
                timeout: this.parameters.timeout,
                success: function (data)
                {
                    var args = arguments[2];
                    if (scb)
                    {
                        if (!self.parameters.otherData)
                            scb.call(this, data, args.statusText, args);
                        else
                            scb.call(this, data, args.statusText, args, self.parameters.otherData);
                    }
                },
                error: function (xhr, ajaxOptions, thrownError)
                {
                    xhrServerObj = xhr;
                }
            });
        }
    }
}

var get1 = Object.create(ajax);
var get2 = Object.create(ajax);

getGet(get1, cb1);
getGet(get2, cb2);

function getGet(req, cb)
{
    req.parameters = { url: "Req" };
    req.callback.success = cb;
    req.get();
}

function cb1()
{
    console.log("cb1");
}
function cb2()
{
    console.log("cb2");
}

答案 1 :(得分:0)

JavaScript中最适合面向对象的开发利用了函数的原型。

首先你要创建一个函数:

Foo = function()
{
};

然后将函数添加到其原型中:

Foo.prototype.Blah = function()
{
   // here you can access 'this'
};

现在Blah()是名为Foo的对象/类的函数。您可以使用new关键字进行实例化,并按预期调用该函数:

var f = new Foo;
f.Blah();

原型也可用于变量成员。 JavaScript中有两种类型的变量成员:静态和非静态。如果您使用编译器(例如Google的闭包编译器),您也可以假装来定义公共成员,受保护成员和私有成员,但在最终版本中,一切都是公共的。

Foo.static_value = 123;  // initialized on load, common to all objects
Foo.prototype.value = 5; // initialized to 5 on construction

在大多数情况下,您希望在常量变量时​​使用静态变量。

然而,可变成员存在陷阱。如果定义对象或数组,则不会复制这些对象,因此相同的引用将出现在所有对象中。在大多数情况下,以下是错误的:

Foo.prototype.ary = [1, 2, 3];
Foo.prototype.obj = { a: 1, b: 2, c: 3 };

解决此问题的方法是初始化构造函数中的数组和对象,如下所示:

Foo = function()
{
  this.ary = [1, 2, 3];
  this.obj = { a: 1, b: 2, c: 3 };
};
Foo.prototype.Blah = function()
{
   this.ary.push(17); // not common to all objects of type Foo
};

然后这些成员的声明使用null:

Foo.prototype.ary = null;
Foo.prototype.obj = null;

这样就可以避免引用另一个对象的问题,这个对象对所有对象都是通用的。

您可能还想使用名称空间,它只是一个变量,以避免以后出现潜在问题。假设你的库是lib,你可以写:

var lib = {};

然后将其作为所有Foo定义的前缀,如:

lib.Foo = function() { ... };

还有一些方法可以从另一个对象中获取一个对象(“扩展”),但这更加先进!