2

我有一个方法如下:

 self.getOrAddCache = function (key, objectFactory) {
        var data = self.getFromCache(key);
        if (!data) {
            data = objectFactory();
            if (data && data != null)
                self.addToCache(key, data);
        }
        return data;
    };

我这样使用:

function getCities()
{
    var cities = getOrAddCache(CacheKeys.Cities, function() {
        var cityArray = new Array();
        // get city informations from service 
        $.ajax({
               type: "GET",
               async: true,
               url: "service/cities",
               success: function (response) {
                    $.each(response, function(index, value) {
                        cityArray.push({
                            name: value.name,
                            id: value.id
                        });
                    });
               }
           });

        if (cityArray.length > 0)
            return cityArray;
        else {
            return null;
        }
    });

    return cities;
}

getCities函数总是返回null,因为getCities不等待完成异步 ajax 请求。

我该如何解决这个问题?(请求必须是异步的)

4

4 回答 4

3

最好的解决方案是使用 Deferred 对象。由于您要求 AJAX 调用是异步的,因此您应该让您的getCities函数返回一个承诺,以便在将来的某个时间返回该数据。

您无需将原始数据存储在缓存中,而是存储这些承诺。

如果你请求一个已经解决的承诺,那将立即完成。如果缓存对象已经有一个挂起的请求,异步 AJAX 调用将被启动,所有等待该承诺的未完成回调将按顺序启动。

像这样的东西应该可以工作,尽管这当然是未经测试的,E&OE 等等等等。

self.getCached = function(key, objectFactory) {
    var def = self.getCache(key);
    if (!def) {
        def = objectFactory.call(self);
        self.addToCache(key, def);
    }
    return def;
}    

function getCities() {
    return getCached(CacheKeys.Cities, function() {
        return $.ajax({
            type: 'GET',
            url: 'service/cities'
        }).pipe(function(response) {
            return $.map(response, function(value) {
                 return { name: value.name, id: value.id };
            });
        });
    });
}

.pipe请注意将 AJAX 响应后处理为所需格式的用法,结果是另一个延迟对象,实际上是后一个对象存储在缓存中。

现在的用法是:

getCities().done(function(cities) {
    // use the cities array
});
于 2012-11-16T12:24:24.907 回答
1

使用回调:

function getCities(callbackFunction)
{
    var cities = getOrAddCache(CacheKeys.Cities, function() {
        var cityArray = new Array();
        // get city informations from service 
        $.ajax({
               type: "GET",
               async: true,
               url: "service/cities",
               success: function (response) {
                    $.each(response, function(index, value) {
                        cityArray.push({
                            name: value.name,
                            id: value.id
                        });
                    });
                    callbackFunction(cityArray);
               }
           });
    });
}

getCities(function(cityArray){
  // do stuff
});
于 2012-11-16T11:29:29.843 回答
1

您不能从异步获取数据的函数返回结果。

将您的 getCities 函数更改为接受回调的函数:

function fetchCities(callback) {
    var cities = getOrAddCache(CacheKeys.Cities, function() {
        var cityArray = new Array();
        // get city informations from service 
        $.ajax({
               type: "GET",
               async: true,
               url: "service/cities",
               success: function (response) {
                    $.each(response, function(index, value) {
                        cityArray.push({
                            name: value.name,
                            id: value.id
                        });
                    });
                    if (callback) callback(cityArray);
               }
           });
    });
}

并像这样使用它:

fetchCities(function(cities) {
   // use the cities array
});

请注意,使用async:true, 使代码等待响应但不使用它在技术上是可行的:这是一种糟糕的做法,它会锁定页面直到服务器响应。

于 2012-11-16T11:29:38.877 回答
0

你好像在自相矛盾。

根据定义,异步的东西不会暂停脚本以等待其执行结束。如果它确实等待,它就不能是异步的。

解决此问题的最佳方法是在您的 ajax 成功函数中添加一个回调函数,将最终结果传递给另一个函数,该函数处理其余的执行。

于 2012-11-16T11:30:59.743 回答