欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解jQuery同步Ajax帶來的UI線程阻塞問題及解決辦法

 更新時間:2017年08月09日 17:07:54   作者:believe66  
本篇文章主要介紹了jQuery同步Ajax帶來的UI線程阻塞問題及解決辦法,具有一定的參考價值,有興趣的可以了解一下

俗話說不作死就不會死,今天作死了一回,寫了一個比較二逼的函數(shù),遇到了同步Ajax引起的UI線程阻塞問題,在此記錄一下。

事情起因是這樣的,因為頁面上有多個相似的異步請求動作,本著提高代碼可重用性的原則,我封裝了一個名為getData的函數(shù),它接收不同參數(shù),只負責(zé)獲取數(shù)據(jù),然后把數(shù)據(jù)return?;镜倪壿媱冸x出來是這樣的:


function getData1(){
    var result;
    $.ajax({
      url : 'p.php',
      async : false,
      success: function(data){
        result = data;
      }
    });

  return result;
}

這里的ajax不能用異步的,否則函數(shù)返回時,result還未賦值,會出錯。所以我加了async:false。看起來好像沒什么問題。我調(diào)用這個函數(shù)可以正常的得到數(shù)據(jù)。

$('.btn1').click(function(){
    var data = getData1();
    alert(data);
});

接下來,要加另外一個功能,由于ajax請求有一定的耗時,所以我需要在發(fā)出請求前頁面有個loading效果,即顯示一張“正在加載”的gif圖片,想必大家也都見過。所以我的處理函數(shù)就變成了這樣:

$('.btn1').click(function(){
    $('.loadingicon').show();
    var data = getData1();
    $('.loadingicon').hide();
    alert(data);
});

請求之前顯示loading圖片,請求完成后把它隱藏??雌饋硪矝]什么問題。為了看清效果,我的p.php代碼sleep了3秒,如下:

<?php
sleep(3);
echo ('aaaaaa');
?>

但是我運行的時候問題出現(xiàn)了,我點擊按鈕并未像預(yù)想的那樣出現(xiàn)這個loading圖片,頁面什么反應(yīng)也沒有。排除良久找到了原因,就在async:false這里。

瀏覽器的渲染(UI)線程和js線程是互斥的,在執(zhí)行js耗時操作時,頁面渲染會被阻塞掉。當(dāng)我們執(zhí)行異步ajax的時候沒有問題,但當(dāng)設(shè)置為同步請求時,其他的動作(ajax函數(shù)后面的代碼,還有渲染線程)都會停止下來。即使我的DOM操作語句是在發(fā)起請求的前一句,這個同步請求也會“迅速”將UI線程阻塞,不給它執(zhí)行的時間。這就是代碼失效的原因。

setTimeout解決阻塞問題

既然明白了問題在哪里,我們就來針對性想辦法。為了不讓同步ajax請求阻塞線程,我想到了setTimeout,把請求的代碼放到sestTimeout中,讓瀏覽器重啟一個線程來操作,不就解決問題了嗎?于是乎,我的代碼就變成了這樣:

$('.btn2').click(function(){
    $('.loadingicon').show();
    setTimeout(function(){
      $.ajax({
        url : 'p.php',
        async : false,
        success: function(data){
          $('.loadingicon').hide();
          alert(data);
        }
      });
    }, 0);
});

setTimeout的第二個參數(shù)設(shè)為0,瀏覽器會在一個已設(shè)的最小時間后執(zhí)行。不管三七二十一先運行起來看看。

結(jié)果loading圖片顯示出來了,但是!??!圖片怎么不動呢,我明明是一張動態(tài)gif圖。這個時候我很快就想到了,雖然同步請求延遲執(zhí)行了,但是它執(zhí)行期間還是會把UI線程給阻塞。這個阻塞相當(dāng)牛逼,連gif圖片都不動了,看起來像一張靜態(tài)圖片一樣。

結(jié)論很明顯,setTimeout治標不治本,相當(dāng)于把同步請求“稍稍”異步了一下,接下來還是會進入同步的噩夢,阻塞線程。方案失敗。

是時候用Deferred了

jQuery在1.5版本之后,引入了Deferred對象,提供的很方便的廣義異步機制。詳情可參看這篇文章http://www.dbjr.com.cn/article/54762.htm。

于是我用Deferred對象改寫了代碼,如下:

function getData3(){
    var defer = $.Deferred();
    $.ajax({
      url : 'p.php',
      //async : false,
      success: function(data){
        defer.resolve(data)
      }
    });
    return defer.promise();
}  

$('.btn3').click(function(){
    $('.loadingicon').show();
    $.when(getData3()).done(function(data){
      $('.loadingicon').hide();
      alert(data);
    });
});

可以看到我在ajax請求中去掉了async:false,也就是說,這個請求又是異步的了。另外請注意success函數(shù)中的這一句:defer.resolve(data),Deferred對象的resolve方法可傳入一個參數(shù),任意類型。這個參數(shù)可以在done方法中拿到,所以我們異步請求來的數(shù)據(jù)就可以以這樣的方式來返回了。

至此,問題得到了解決。Deferred對象如此強大且方便,我們可以好好利用它。

我的全部測試代碼如下,有意的同學(xué)可以拿去測一下:

<button class="btn1">async:false</button>
<button class="btn2">setTimeout</button>
<button class="btn3">deferred</button>
  
<img class="loadingicon" style="position:fixed;left:50%;top:50%;margin-left:-16px;margin-top:-16px;display:none;" src="loading2.gif" alt="正在加載" />
<script>

  function getData1(){
    var result;
    $.ajax({
      url : 'p.php',
      async : false,
      success: function(data){
        result = data;
      }
    });

    return result;
  }

  $('.btn1').click(function(){
    $('.loadingicon').show();
    var data = getData1();
    $('.loadingicon').hide();
    alert(data);
  });


  
  $('.btn2').click(function(){
    $('.loadingicon').show();
    setTimeout(function(){
      $.ajax({
        url : 'p.php',
        async : false,
        success: function(data){
          $('.loadingicon').hide();
          alert(data);
        }
      });
    }, 0);
  });



  function getData3(){
    var defer = $.Deferred();
    $.ajax({
      url : 'p.php',
      //async : false,
      success: function(data){
        defer.resolve(data)
      }
    });
    return defer.promise();
  }  

  $('.btn3').click(function(){
    $('.loadingicon').show();
    $.when(getData3()).done(function(data){
      $('.loadingicon').hide();
      alert(data);
    });
  });</script>

PS:Firefox有做優(yōu)化?

上述問題在chrome和IE9中測試結(jié)論一致。但是我在Firefox中測試時,同步ajax并未阻塞掉UI線程,也就是說這個問題根本不存在。我用其他代碼做了測試,在Firefox中js線程確實是會阻塞UI線程,這個沒有疑問。那可能的一個猜測就是Firefox對同步ajax做了優(yōu)化,事實到底是什么,我暫未得知。有高人知道還請指點。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • JQuery觸發(fā)事件例如click

    JQuery觸發(fā)事件例如click

    JQuery觸發(fā)事件的通常寫法,比如click事件的觸發(fā)如下所示,感興趣的朋友可以參考下
    2013-09-09
  • jquery.validate提示錯誤信息位置方法

    jquery.validate提示錯誤信息位置方法

    這篇文章主要介紹了jquery.validate提示錯誤信息位置方法,實例分析了jquery.validate實現(xiàn)提示錯誤信息位置的相關(guān)技巧,需要的朋友可以參考下
    2016-01-01
  • jQuery實現(xiàn)簡易聊天框

    jQuery實現(xiàn)簡易聊天框

    這篇文章主要為大家詳細介紹了jQuery實現(xiàn)簡易聊天框,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • 40個有創(chuàng)意的jQuery圖片和內(nèi)容滑動及彈出插件收藏集之三

    40個有創(chuàng)意的jQuery圖片和內(nèi)容滑動及彈出插件收藏集之三

    在網(wǎng)頁的首頁或圖片專題頁面很多地方都會用到圖片滑動插件來循環(huán)切換多張圖片,并且用戶可以點擊左右按鈕來切換圖片。
    2012-01-01
  • JQuery?AJAX操作代碼

    JQuery?AJAX操作代碼

    jQuery底層AJAX實現(xiàn),其返回其創(chuàng)建的XMLHttpRequest對象,大多數(shù)情況下無需直接操作該函數(shù),除非需要操作不常用的選項,以獲得更多的靈活性,這篇文章給大家介紹JQuery AJAX操作代碼,感興趣的朋友一起看看吧
    2022-12-12
  • jQuery中:only-child選擇器用法實例

    jQuery中:only-child選擇器用法實例

    這篇文章主要介紹了jQuery中:only-child選擇器用法,實例分析了:only-child選擇器的功能、定義及匹配父元素的唯一子元素使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-01-01
  • jQuery實現(xiàn)的網(wǎng)格線繪制方法

    jQuery實現(xiàn)的網(wǎng)格線繪制方法

    這篇文章主要介紹了jQuery實現(xiàn)的網(wǎng)格線繪制方法,涉及jQuery針對頁面元素的獲取及樣式動態(tài)操作相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • jquery+json實現(xiàn)動態(tài)商品內(nèi)容展示的方法

    jquery+json實現(xiàn)動態(tài)商品內(nèi)容展示的方法

    這篇文章主要介紹了jquery+json實現(xiàn)動態(tài)商品內(nèi)容展示的方法,涉及jQuery操作及解析json格式數(shù)據(jù)的相關(guān)技巧,需要的朋友可以參考下
    2016-01-01
  • 使用js顯示當(dāng)前時間示例

    使用js顯示當(dāng)前時間示例

    這篇文章主要介紹了使用js顯示當(dāng)前時間示例,這里也用到了jquery,讓得把它也要引入到頁面中
    2014-03-03
  • 一個背景云變換js特效 鼠標移動背景云變化

    一個背景云變換js特效 鼠標移動背景云變化

    分享一個背景云變換js特效隨著鼠標的移動,背景云會不斷的變化位置和形狀,感興趣的朋友可以研究下
    2012-12-12

最新評論