ajax請求 遮罩不生效解決方案以及引發思考

  • 遮罩不生效

今天同事丟給我一個很小的需求,在幾個報表的頁面加入一個遮罩。拿到需求我就知道肯定沒那麼簡單,如果只是簡單的加一個遮罩他自己肯定早就做了,根本不會特意和我說,來讓我做。

果然,直接設置ajax的beforeSend:loadMask()以及unLoadMask()後遮罩並沒有顯示出來。

debug進行調試,發現遮罩生效了只是在正常請求模式下沒有展示出來而已。聽起來似乎這句話有點彆扭,實際上就是渲染線程被阻塞了。

  • 解決方案

       $.ajax({        	
            async: true, //直接設置請求爲異步,或者刪除這一行ajax默認異步
            url: _uri,
            type: 'POST',
            dataType: "JSON",
            data: {
            },
            beforeSend:loadMask(),
            success: function (data) {
	            unLoadMask();
                alert('成功');
            },
            error: function () {
            	unLoadMask();
            	alert('失敗');
            }
        });

因ajax設置了同步,而GUI渲染線程與JS引擎線程是互斥的,所以此時渲染線程被阻塞導致遮罩的樣式沒有被加載出來。

而直接設置ajax請求爲異步的時候,瀏覽器會新開一個線程來執行,當然回調的時候還是js的單線程性。只是此時GUI渲染線程不會被阻塞。

  • 拓展

1.GUI渲染線程

負責渲染瀏覽器界面,解析HTML,CSS,構建DOM樹,佈局和繪製等等。

當界面需要重繪時,該線程就會執行

2.JS引擎線程

JS引擎線程負責解析Javascript腳本,運行代碼。

JS引擎一直等待着任務隊列中任務的到來,然後加以處理,瀏覽器無論什麼時候都只有一個JS線程在運行JS程序

注意,GUI渲染線程與JS引擎線程是互斥的,所以如果JS執行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞。(這就是出現以上ajax請求阻塞了渲染線程的原因所在)

3.事件觸發線程

歸屬於瀏覽器而不是JS引擎,用來控制事件循環,當JS引擎執行代碼塊如setTimeOut時(也可來自瀏覽器內核的其他線程,如鼠標點擊、AJAX異步請求等),會將對應任務添加到事件線程中

當對應的事件符合觸發條件被觸發時,該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理

注意,由於JS的單線程關係,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閒時纔會去執行)

4.定時觸發器線程

setInternal與setTimeout所在線程,瀏覽器定時計數器並不是由JavaScript引擎計數的,(因爲JS引擎是單線程的, 如果處於阻塞線程狀態就會影響記計時的準確),因此通過單獨線程來計時並觸發定時(計時完畢後,添加到事件隊列中,等待JS引擎空閒後執行)

5.異步http請求線程

在XMLHttpRequest在連接後是通過瀏覽器新開一個線程請求,將檢測到狀態變更時,如果設置有回調函數,異步線程就產生狀態變更事件,將這個回調再放入事件隊列中。再由JavaScript引擎執行。

  • 盲區

可能會有人不是很理解JS的單線程,明明ajax是一種異步請求,爲什麼js還是單線程的呢。其實實現多線程的是瀏覽器,在需要異步請求的時候由瀏覽器新開一個線程來執行其方法,在請求結束之後可以利用回調函數進行執行獲得的參數處理等等。實現的方式是將請求放入一個JS的執行隊列中依次執行(這也是JS的單線程體現),這是回調函數和普通函數公用的一個隊列。

  • 題外話

也幸好是同事覺得這個小問題不知道怎麼解決,隨便就丟給我讓我幫忙解決一下,自己纔有機會去處理並且學習。總之,解決問題就是對自己的一個提升。

如果我的這篇文章對你有幫助或者有任何疑點都歡迎在評論區交流!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章