0

我一直在尝试获取我的 ajax 请求以保证从我加载的模板中得到响应。

基本上,如果我运行我的代码来返回我的延迟对象 $.then() 在我拥有我的模板对象之前调用。这仅在第一次运行时发生。

我用这个把头发扯掉了!

我的ajax调用:

var ajax = {
    getTemplate: (function (id) {
    /// <summary>
    ///     This method when used with $.Deferred fetches a html string 
    ////    containing the template appliciable 
    ///     to the the supplied id.
    ///     The ajax request object is cached upon the first request and is
    ///     returned by the cache 
    ///     upon each subsequent request.
    /// </summary>
    /// <param name="id" type="String">
    ///     The id that matches the filename to request the template object
    ///     from.
    /// </param>
    /// <returns type="jqXHR">
    ///      A superset of the XMLHTTPRequest object that impliments the
    ///      promise interface.
    /// </param>

    var cache = {}; // private cache

    // Gets assigned to getTemplate.
    return function (id) {

    var url = "/templates/" + id + ".tpl";
    return cache[id]|| $.ajax({
           url: url,
           dataType: "html",
           success: function (data) {

               //ajax.getTemplate(id, data);
               cache[id] = data;
           },
           error: function (XMLHttpRequest, textStatus, errorThrown) {
               log("template request " + id, 
                   XMLHttpRequest, 
                   textStatus, 
                   errorThrown);
           }
           });
        };
    } ())
};

我在我的方法中这样调用它:

$.when(ajax.getTemplate("tooltip-attributes")()).then(function (template) {

    if (template) {
       // Do my template stuff here.
    }

 });
4

4 回答 4

1

我有时喜欢用我自己的 deferred 包装 ajax 调用,因为我不想公开 ajax deferred,而是根据 ajax 调用返回的任何自定义对象来解决它。例如:

function myFunction(resolved) {
    var deferred = $.Deferred();
    if ($.IsNullOrEmpty(resolved)) {
        deferred.reject("Parameters are required.");
    } else {
        $.ajax({
            type: "POST",
            url: "/something/somewhere",
            data: { someParameter : "someValue" },
            dataType: "json"
        }).done(function (result) {
            if (result.success === false) {
                deferred.reject({
                    success: false,
                    reason: "you fail"
                });
            } else {
                deferred.resolve({
                    success: true,
                    result: result.someData
                });
            }
        });
    }
    return deferred.promise();
}

然后我将创建另一个延迟承诺来解决它:

var deferred = $.Deferred(),
    promise = deferred.promise();

promise
    .then(myFunction)
    .then(someOtherDependentFunction)
    .fail(function (response) {
        // do fail stuff
    })
    .done(function () {
        // do done stuff
    });

你也可以在这里使用“when”来进行异步,而不是像那样链接它们。

然后解决问题

deferred.resolve({
    member: item
});

我喜欢这个,因为它允许我通过使 someOtherDependentFunction 成为使用解析数据并返回承诺的任何其他函数来构建动态函数链。显然,还有很多其他方法可以使用它。

于 2015-01-06T04:22:17.880 回答
0

你应该看看这个教程,尤其是“推迟你的延期”部分。这个关于jQuery.pipe()函数的文档也很有趣!

问题是在 $.when() 中调用的每个函数都需要调用它的 promise() 函数,以便 $.when() 等待每个函数的完成。显然从缓存中返回一个对象并不能解决延迟!

首先让你的函数总是返回一个 $.Deferred 对象,比如已经描述过的 BonyT 并让它调用 promise() 函数:

getTemplate: (function(id) {
    return $.Deferred(function (id) {...}
    .promise();
})()

您的内部返回提供了一个已经存在的缓存对象或一个 $.ajax xmlhttp 请求。后者总是返回一个在其 .done() 回调处理函数中调用 .resolve() 函数的 Deferred 对象——但缓存版本没有!因此,如果从本地缓存对象中提取数据,您必须手动调用 $.Deferred.resolve() 或 $.Deferred.reject()。

getTemplate: (function(id) {
    if (cache.hasOwnProperty(id)) {
        var dfd = $.Deferred();
        var filtered = dfd.pipe(function(value) {
            return cache[value];
        });
        return dfd.resolve(id);
    } else {
        $.ajax({
            url: url,
            dataType: "html"
        })
        .done(function(result) {
            /*fires when resolved*/
            return result;
        })
        .fail(/*fires only when rejected*/)
        .always(/*fires when both rejected or resolved*/);
    }
})()

顺便说一句,不要再使用 .success() 和 .error() 了,因为它们将在 jQuery 1.8 “弃用通知”中被弃用。请改用 .done()、.fail() 和 .always()。

于 2011-09-30T10:22:17.200 回答
0

看起来您没有正确创建 Deferred。

尝试将顶部功能更改为

// Gets assigned to getTemplate.
return $.Deferred(function (id) {
于 2011-06-13T10:46:50.643 回答
0

可能让您感到困惑的是有一个外部id和一个内部id......两者都没有被分配。

外部id实际上可以消失 - 只有当您在自我执行程序调用中传递一个 id 时才会分配它。

现在,实际的解决方法是正确调用内部函数(返回的那个ajax.getTemplate()):

$.when(ajax.getTemplate()("tooltip-attributes")).then(...);

请注意,“工具提示属性”现在出现在第二组括号中。但是有一个很好的理由不这样调用它——即每个ajax.getTemplate()调用都有自己的独立缓存,而不是一个公共缓存。这样做会更有意义:

var templateGetter = ajax.getTemplate();//Assign the returned function to make it reusable
...
$.when(templateGetter("tooltip-attributes")).then(...);

就个人而言,我发现整个构造令人困惑,并且可能会使用 Crockford 风格的模块模式,如下所示:

var AJAX = {
    var cache = {}; // private cache of jqXHR objects (promises)
    var getTemplate = function (id) {
        var url = "/templates/" + id + ".tpl";
        if(!cache[id]) {
            cache[id] = $.ajax({
                url: url,
                dataType: 'html',
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    log("template request " + id, XMLHttpRequest, textStatus, errorThrown);
                }
            });
        }
        return cache[id];
    };
    return {
        getTemplate: getTemplate
    }
};

现在,AJAX.getTemplate()保证返回一个承诺。

AJAX.getTemplate("tooltip-attributes").then(function (template) {
    if (template) {
        // Do my template stuff here.
    }
});
于 2015-01-06T13:56:33.943 回答