如何避免手动缓存返回错误的请求?

How to avoid manually caching a request that returned an error?

我创建了一个模块(遵循 Javascript 的模块模式),它发出 http 请求、缓存和 returns 结果:

var requestService = (function($) {

    var cache = {};

    var get = function(date) {
        var params = date ? {'date': date} : {};
        return $.getJSON('http://my/url', params, function( result ){});
    };

    var fetchData = function(date) {
        if (!cache[date]) {
            cache[date] = get(date);
        }

        return cache[date].done(function(myData) {
            return new Promise(function(resolve,reject) {
                resolve(myData);
            });
        });
    };

    return {
        fetchData: fetchData
    };
})(jQuery);

我的问题是,即使出现错误(例如:主机暂时无法访问),结果也会被缓存。我不希望发生这种情况。

我以为只有请求成功才会调用done()函数,其实不然。我应该添加一个缓存 [date].fail() 并将其自身设置为 null 吗?我的意思是:

return cache[date].done(function(myData) {
    return new Promise(function(resolve,reject) {
        resolve(myData);
    });
}).fail(function(myData) {
    cache[date] = null;
    return new Promise(function(resolve,reject) {
        reject(myData);
    });
});

下面是我的 requestService 在另一个模块中的调用方式:

requestService.fetchData(myDate).done(function(myData) {
    // code when successful
}).fail(function(d, textStats, error) {
    // error
});

没关系,该代码经过一些调整后就可以正常工作。在我的 fetchData 方法中,我正在检查对象是否为空(因此未定义 为空),并且我添加了一个使缓存 [date] 无效的 fail() 方法。我现在执行以下操作:

var requestService = (function($) {

    var cache = {};

    var get = function(date) {
        var params = date ? {'date': date} : {};
        return $.getJSON('http://my/url', params, function( result ){});
    };

    var fetchData = function(date) {
        // now also checks for null
        if ($.isEmptyObject(cache[date])) {
            cache[date] = get(date);
        }

        return cache[date].done(function(myData) {
            return new Promise(function(resolve,reject) {
                resolve(myData);
            });
        }).fail(function(myData) {
        return new Promise(function(resolve,reject) {
            // nullifies cache[date]
            cache[date] = null;
            reject(myData);
        });
    };

    return {
        fetchData: fetchData
    };
})(jQuery);

donefail 不支持链接回调结果,你的 return new Promise 绝对没有意义。此外,您似乎正在尝试使用 Promise constructor antipattern。您的代码所做的只是 return ajax 按原样承诺(有效,因为您可以链接到它)。

the results are cached even if there's an error

是 - 通过存储承诺,整个请求结果都会被缓存,而不仅仅是在成功的情况下。

Should I add a rejection handler, setting itself to null?

是的,这正是您需要做的:

var requestService = (function($) {
    var cache = {};

    function get(date) {
        var params = date ? {'date': date} : {};
        return $.getJSON('http://my/url', params);
    }

    function fetchData(date) {
        if (!cache[date]) {
            cache[date] = get(date);
            cache[date].fail(function(err) {
                cache[date] = null; // retry next time
            });
        }
        return cache[date];
    }

    return {
        fetchData: fetchData
    };
})(jQuery);

如果你想return一个本地承诺,使用

function fetchData(date) {
    if (!cache[date]) {
        cache[date] = Promise.resolve(get(date)).catch(function(err) {
            cache[date] = null; // retry next time
            throw err;
        });
    }
    return cache[date];
}