javascript - Jquery $.when 阻止代码执行和 UI 更新?

标签 javascript jquery

我们在单页应用程序中使用 JQuery。 我们的 boostrapper 是应用程序的起点,看起来像这样:

define('homebootstrapper',
    ['jquery', 'config', 'homerouteconfig', 'presenter', 'dataprimer', 'binder'],
    function ($, config, homeRouteConfig, presenter, dataprimer, binder) {
        var
            run = function () {
                $('#busyIndicator').activity(true);

                $.when(dataprimer.fetch())                
                    .done(function () {
                       // $('#busyIndicator').activity(false);
                    });
            };

        return {
            run: run
        };
    });

被调用的 dataprimer 看起来像这样:

define('dataprimer',
    ['ko', 'datacontext', 'config'],
    function (ko, datacontext, config) {

        var logger = config.logger,

            fetch = function () {

                return $.Deferred(function (def) {

                    console.log('in deferred');   
                    $.when(LongTimeProcessing())
                    .pipe(function () {                        
                        logger.success('Fetched data');
                    })

                    .fail(function () { def.reject(); })

                    .done(function () { def.resolve(); });

                }).promise();
            };

        return {
            fetch: fetch
        };
    });

function LongTimeProcessing(options) {
    console.log('in when');
    return $.Deferred(function (def) {
        var results = options;
        for (var i = 0; i < 10; i++) {
            var x = i;
            $('#counter').html(x);
        }
        def.resolve(results);
    }).promise();
}

$('#busyIndi​​cator').activity(true); 应显示基于 SVG 或 VML 的进度动画。这很好用,除非使用 JQuery $.when

使用此示例代码,我们尝试创建一个需要一些时间并称为“LongTimeProcessing”的方法(而不是通常通过放大使用的对后端的 ajax 调用)

我们看到,当我们使用 jquery 时,busyindicator 不工作(read: 不显示),直到 dataprimer 返回 def.resolve()。这似乎会阻止所有 UI 更新。此外,LongTimeProcessing 方法的计数器值仅显示此循环的最后一个值。它已执行但永远不可见。

我们做错了什么?我们应该如何处理。

最佳答案

必须屈服于事件处理循环,以允许 UI 更新和处理未完成的事件。这只会在您自己的代码执行完毕时发生。

您的 LongTimeProcessing 函数不会执行此操作,它会启动一个循环并且在该循环完成之前不会将控制权返回给浏览器。

您可以通过使用 setTimeout 来处理循环迭代来实现您想要的:

function LongTimeProcessing(options) {
    console.log('in when');
    return $.Deferred(function (def) {
        var results = options;

        var i = 0;

        (function iterate() {
            $('#counter').html(i);
            if (i < 10) {
                ++i;
                setTimeout(iterate, 250);
            } else {
                def.resolve(results);
            }
        })();

    }).promise();
}

setTimeout 的调用允许函数在第一次调用iterate() 后立即终止,允许浏览器的事件处理循环处理 UI 更新,然后继续当计时器结束时进入下一次迭代。

关于javascript - Jquery $.when 阻止代码执行和 UI 更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15290817/

相关文章:

javascript - 聚合两个对象数组

javascript - Date.parse 的正确日期格式应该是哪种?

javascript - 从黑白到彩色显示图像,就像它正在加载一样(从左到右)

jquery - 可拖动和可放置在 WordPress 管理中不起作用

javascript - 如何修复无法读取 free-jqgrid 中未定义的属性 'rowIndexes'

javascript - Vue 3 ref 未更新为模板上的组件

javascript - 可观察到的 knockout 是否可以实现数字动画行为?

javascript - 如何抑制javascript异常?

Javascript 函数无法返回元素

javascript 等待 DOM 元素实际绘制并完成