2013-03-08 42 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