2013-03-08 58 views
1

我们在单页面应用程序中使用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(); 
} 

线$('#busyIndicator').activity(true); 应该显示进度动画基于SVG或VML。这个效果很好,除非使用JQuery $。当

有了这个示例代码,我们试图创建一个需要一段时间的方法,它被称为'LongTimeProcessing'(而不是对后端的ajax调用,它是通常通过放大来使用)

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

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

回答

3

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

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

你可以实现你想要的使用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更新,然后在计时器过去时进入下一次迭代。

+0

工程就像一个魅力,谢谢。我假设在打电话给后端时,放大功能会默认执行此操作? – Thomas 2013-03-08 10:53:03

+0

@Thomas不知道,但如果后端的调用使用AJAX,那么它是隐式异步的。 – Alnitak 2013-03-08 10:59:14