jQuery Ajax同步參數致使瀏覽器假死怎麼辦

事情原由是這樣的,由於頁面上有多個類似的異步請求動做,本着提升代碼可重用性的原則,我封裝了一個名爲getData的函數,它接收不一樣參數,只負責獲取數據,而後把數據return。基本的邏輯剝離出來是這樣的: 代碼以下 複製代碼 function getData1(){        var result;        $.ajax({            url : 'p.php',            async : false,            success: function(data){                result = data;            }        });    return result; }   這裏的ajax不能用異步的,不然函數返回時,result還未賦值,會出錯。因此我加了async:false。看起來好像沒什麼問題。我調用這個函數能夠正常的獲得數據。 代碼以下 複製代碼 $('.btn1').click(function(){        var data = getData1();        alert(data); });   接下來,要加另一個功能,因爲ajax請求有必定的耗時,因此我須要在發出請求前頁面有個loading效果,即顯示一張「正在加載」的gif圖片,想必你們也都見過。因此個人處理函數就變成了這樣: 代碼以下 複製代碼 $('.btn1').click(function(){        $('.loadingicon').show();        var data = getData1();        $('.loadingicon').hide();        alert(data); });   請求以前顯示loading圖片,請求完成後把它隱藏。看起來也沒什麼問題。爲了看清效果,個人p.php代碼sleep了3秒,以下:php

  可是我運行的時候問題出現了,我點擊按鈕並未像預想的那樣出現這個loading圖片,頁面什麼反應也沒有。排除良久找到了緣由,就在async:false這裏。   瀏覽器的渲染(UI)線程和js線程是互斥的,在執行js耗時操做時,頁面渲染會被阻塞掉。當咱們執行異步ajax的時候沒有問題,但當設置爲同步請求時,其餘的動做(ajax函數後面的代碼,還有渲染線程)都會中止下來。即便個人DOM操做語句是在發起請求的前一句,這個同步請求也會「迅速」將UI線程阻塞,不給它執行的時間。這就是代碼失效的緣由。 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的第二個參數設爲0,瀏覽器會在一個已設的最小時間後執行。無論三七二十一先運行起來看看。   結果loading圖片顯示出來了,可是!!!圖片怎麼不動呢,我明明是一張動態gif圖。這個時候我很快就想到了,雖然同步請求延遲執行了,可是它執行期間仍是會把UI線程給阻塞。這個阻塞至關牛逼,連gif圖片都不動了,看起來像一張靜態圖片同樣。   結論很明顯,setTimeout治標不治本,至關於把同步請求「稍稍」異步了一下,接下來仍是會進入同步的噩夢,阻塞線程。方案失敗。 是時候用Deferred了   jQuery在1.5版本以後,引入了Deferred對象,提供的很方便的廣義異步機制。詳情可參看阮一峯老師的這篇文章  因而我用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函數中的這一句:defer.resolve(data),Deferred對象的resolve方法可傳入一個參數,任意類型。這個參數能夠在done方法中拿到,因此咱們異步請求來的數據就能夠以這樣的方式來返回了。   至此,問題獲得瞭解決。Deferred對象如此強大且方便,咱們能夠好好利用它。   個人所有測試代碼以下,有意的同窗能夠拿去測一下: 代碼以下 複製代碼async:falsesetTimeoutdeferredajax

PS:Firefox有作優化?   上述問題在chrome和IE9中測試結論一致。可是我在Firefox中測試時,同步ajax並未阻塞掉UI線程,也就是說這個問題根本不存在。我用其餘代碼作了測試,在Firefox中js線程確實是會阻塞UI線程,這個沒有疑問。那可能的一個猜想就是Firefox對同步ajax作了優化,事實究竟是什麼,我暫未得知。有高人知道還請指點。chrome

相關文章
相關標籤/搜索