Javascript / JQuery - 如何在完成前一个函数时调用一个函数

时间:2014-12-16 19:37:59

标签: javascript jquery deferred

我使用以下Javascript函数来显示图片库。

function disp_pics(currObj,table){
    if(currObj != "none"){
        $("div .checkout2").removeClass("checkout2").addClass("checkout");
        $(currObj).closest("div").removeClass("checkout").addClass("checkout2");
    }

    function getData(table){
        return $.ajax({
            url: "newphoto_gallery_display.php",
            type: "GET",
            data: {
                table: table
            },
            dataType: "html"
        });
    }

    function display_result(data){
        var dfd = new $.Deferred();
        dfd.done(equalise);
        $("#ajaxoutput").html(data);
        setTimeout(function() {
            dfd.resolve();
        }, 1000);
    }

    function equalise(){
        var highestBox = 0;
        $('.photodisplay').each(function(){
            if($(this).height() > highestBox)  {
                highestBox = $(this).height(); 
            }
        });  
        $('.photodisplay').height(highestBox);
    }

    var promise=getData(table);
    promise.success(function (data) {
        promise.done(display_result(data));
    });
};

函数getData从数据库中提取图片数据。函数display_result然后将该数据输出到div id" ajaxoutput"。图片与相关数据一起显示在框中(带边框的HTML表格)。然后调用函数equalize以使所有框具有相同的高度。

如果没有display_result中的时间延迟,则在显示所有图片和数据之前调用均衡功能,从而弄乱显示器。有没有办法消除时间延迟,只有当display_result将所有数据输出到ajaxoutput div时才调用均衡函数?

我已经尝试过各种各样的延期&$。然后.......然后....组合,但是没有设法达到预期的结果而不会延迟脚本,这不是理想的。任何建议都会受到欢迎。

3 个答案:

答案 0 :(得分:5)

如果问题是您需要知道您应用于#ajaxoutput的HTML的所有图像何时被加载(因此浏览器已知其大小),那么您可以这样做监视您添加到HTML的每个图像的onload事件:

function display_result(data){
    var dfd = new $.Deferred();
    var imgWaiting = 0;
    $("#ajaxoutput").html(data).find("img").each(function() {
        if (!this.complete) {
            // img is still loading, install a load handler so we know when it's done
            ++imgWaiting;
            this.onload = this.onerror = function() {
               --imgWaiting;
               if (imgWaiting === 0) {
                   dfd.resolve();
               }
            }
        }
    });
    if (imgWaiting === 0) {
         dfd.resolve();
    }
    return dfd.promise();
}

然后,你可以这样做:

return getData(table).then(display_result).then(equalise);

这是一个经典的设计模式,承诺用于序列化多个异步操作。

答案 1 :(得分:2)

你需要摆脱超时延迟,因为它不能保证足够长时间才能加载图像(慢速服务器,慢速互联网等)。

不幸的是"正确"您一直在寻找的解决方案并不是最简单的,主要是因为您只能在语句$("#ajaxoutput").html(data)将它们放置到位后才能访问感兴趣的img节点。在该声明之后的声明中,将不确定(由于浏览器行为)图像是否已经加载(来自缓存)。只需附加一个" onload"处理程序因此不可靠。

解决方法是创建一组屏幕外的img节点,这些节点反映了"#ajaxoutput"和#34; promisify"他们以他们的'src'在附加" onload"之后设置属性。 (和#34; onerror")处理程序。

代码不易遵循,所以我尽力提供解释性评论。

function display_result(data) {
    //First a function that creates a promisified <img> node, and returns its promise.
    //<img> nodes created here are not appended to the DOM.
    function imgPromise(index, imgNode) {
        return $.Deferred(function(dfrd) {
            //Note the order here - the onload/onerror handler is attached before the src attribute is set.
            //Note also that both onload/onerror cause the deferred to be resolved, as you don't want any failures to prevent calling `equalise()`.
            $("<img/>").on('load error', dfrd.resolve).attr('src', imgNode.src);
        }).promise();
    }

    //A lot happens in the next line ...
    // * "#ajaxoutput" is given some HTML
    // * any freshly created image nodes in "#ajaxoutput" are discovered
    // * `imgPromise()` is called for each img node in turn and the returned promises are stuffed into an array
    // * the array is assigned to local var `promises`.
    var promises = $("#ajaxoutput").html(data).find("img").map(imgPromise);

    //Finally, `$.when()` returns a promise that is resolved when all `promises` have settled.
    //This "summary promise" is returned.
    return $.when.apply(null, promises);
}

如果没有评论,你会发现这实际上非常简洁,希望不那么可怕。

function display_result(data) {
    function imgPromise(index, imgNode) {
        return $.Deferred(function(dfrd) {
            $("<img/>").on('load error', dfrd.resolve).attr('src', imgNode.src);
        }).promise();
    }
    var promises = $("#ajaxoutput").html(data).find("img").map(imgPromise);
    return $.when.apply(null, promises);
}

请致电如下:

getData(table).then(display_result).then(equalise);

答案 2 :(得分:-1)

你可以同步运行它们吗?

function display_result(data){
    $("#ajaxoutput").html(data);
    equalise();
}

我非常确定.html函数是一个同步调用,所以你的调整大小将在此之后发生。

已编辑:来自您的ajax调用的数据是什么样的?它只是一堆img标签吗?如果是这样,你可能最好在ajax中加载图像并自己将其编码到html中。