iT邦幫忙

2

jQuery $.ajax重複呼叫資料,導至畫面卡住

頁面的資料因需要即時性的關系,大概每1秒左右會呼叫一次ajax,並清除瀏覽器上的畫面然後再把取得的資料加到頁面上,反覆下來幾百次後,畫面會卡住,無法流暢的去操作畫面。

目前是有在ajax cache設定成false,但測試後還是有一樣的問題。
想請教各位這是什麼原因造成的?又該如何解決這個問題?

感謝各位~

function SetDetail(){
    $.ajax({
        crossDomain: true,
        url: url,
        method: "POST",
        data: obj,
        cache:false,
        success: function (response) {
            $('.tablebox').children().remove();
            $.each(response,function(i,v){
                var $ul = $('<ul/>').addClass('item')
                $ul.append('<li>'+v.ID+'</li>');
                $ul.append('<li>'+v.Name+'</li>');
                $ul.append('<li>'+v.County+'</li>');
                $('.tablebox').append($ul);
            })
        }
    });
}
setInterval(function(){SetDetail();},1000);
看更多先前的討論...收起先前的討論...
石頭 iT邦研究生 2 級 ‧ 2020-08-05 10:50:59 檢舉
麻煩提供程式碼
沒有程式碼 是請我們觀落音嗎XDD
ShawnL iT邦新手 5 級 ‧ 2020-08-05 11:15:10 檢舉
觀落音一下應該是 Job Queue 那塊與各種事件操作下來堆積導致的堵塞,可參考:
https://pjchender.blogspot.com/2017/08/javascript-learn-event-loop-stack-queue.html
https://www.youtube.com/watch?v=8aGhZQkoFbQ
fillano iT邦超人 1 級 ‧ 2020-08-05 11:23:57 檢舉
恐怕記憶體也用很多...開chrome的工作管理員看一下。另外,開發人員工具裡有Memory Profiling工具,可以拿來試試看
player iT邦大師 1 級 ‧ 2020-08-05 11:46:32 檢舉
自己放個全域變數
做避免重複進入的判斷
很難嗎?
就等做完再進去啊
froce iT邦大師 1 級 ‧ 2020-08-05 12:50:36 檢舉
rxjs...
用debounce
fillano iT邦超人 1 級 ‧ 2020-08-05 16:54:57 檢舉
改用websocket也是可以考慮的方案,http的overhead比較重,這麼頻繁的request等於是攻擊XD,而websocket是有資料才從伺服器端送過來...

2 個回答

5
japhenchen
iT邦高手 1 級 ‧ 2020-08-05 12:21:15

ajax是非同步模式,你前項工作可能沒完成,後面又來個新的ajax request ...........

不卡都難

解決方法,不用setinterval,用settimeout

function SetDetail(){
    $.ajax({
        crossDomain: true,
        url: url,
        method: "POST",
        data: obj,
        cache:false,
        success: function (response) {
            $('.tablebox').children().remove();
            $.each(response,function(i,v){
                var $ul = $('<ul/>').addClass('item')
                $ul.append('<li>'+v.ID+'</li>');
                $ul.append('<li>'+v.Name+'</li>');
                $ul.append('<li>'+v.County+'</li>');
                $('.tablebox').append($ul);
            })
            setTimeout(SetDetail,1000);            // 跑完上述工作......再設定一次timeout,周而復始,保証不會同時有兩個ajax在工作
        }
    });
}

//這個搬進document ready裡
$(document).ready(function () {
    setTimeout(SetDetail,1000);  // ←只讓他跑一次
);

再打個邊爐

為什麼要$(document).ready.............
因為這事件只會發生在頁面BODY完成載入之後,不然如果你把這個js檔掛在<head></head>裡,就會發生找不到你要的elements狀況,或許JQ已有處理好這鳥事,但絕不是個好習慣

也許是你引用的 setinterval(....) 那句刻意省掉ready或 body onload........那就當我沒打這邊爐吧

再打一個邊,ajax非同步是什麼意思.....就是在發動AJAX時並不會死鎖你的系統(或瀏覽器),AJAX畢竟是網路操作,要是網路塞車、斷線、或是電腦正在烤肉片.....你的AJAX就不會馬上完成工作,你用setinterval並不會檢查上一個ajax是否已經完成工作,一秒後又再發動一個新的AJAX..............如果網路持續塞,你的未完成工作就會一直堆積,直到瀏覽器受不鳥發出哀號........其實是警告,告訴你你的網站似乎有些問題沒有回應,然後你的記憶體也會跟我的錢包一樣,愈來愈乾扁.....

補一下浩大的指導

function SetDetail(){
    $.ajax({
        crossDomain: true,
        url: url,
        method: "POST",
        data: obj,
        cache:false,
        success: function (response) {
            $('.tablebox').children().remove();
            $.each(response,function(i,v){
                var $ul = $('<ul/>').addClass('item')
                $ul.append('<li>'+v.ID+'</li>');
                $ul.append('<li>'+v.Name+'</li>');
                $ul.append('<li>'+v.County+'</li>');
                $('.tablebox').append($ul);
            })
            setTimeout(SetDetail,1000);
        },
        error: function(){
            setTimeout(SetDetail,1000);  
        }
    });
}
$(document).ready(function () {
    setTimeout(SetDetail,1000);
);
4
浩瀚星空
iT邦超人 1 級 ‧ 2020-08-05 12:45:13

使用ajax,由於是非同步的關係。
如果是需要計時運行,要事先了解到幾件事

1.是否可以後蓋前行為。
2.是否運行的動作能在時限內完成。(這點很重要)
3.是否有清畫面或是蓋元件的動作。

一般來說,ajax的動作,如果需要定時處理的。我大多不會用1秒來處理。
依照你的程式碼來看,你因該是需要讀取資料並做each調整畫面。
使用1秒的時間太短了。你會無形中造成堆積程序而把瀏覽器給炸了。

基本如果需要有即時性。但讀取資料會超過1秒的情況。
我會建議用一個ajaxing的參數來做判斷。讓你的程序保証不會超過2次ajax請求。
大略如以下的寫法

    var ajaxing=0;//預設動作為0
    setInterval(function(){
        if(ajaxing==0){//判斷還未開始ajax
            ajaxing=1;//設定ajax開始
            $.ajax({
                crossDomain: true,
                url: url,
                method: "POST",
                data: obj,
                cache:false,
                success: function (response) {
                    $('.tablebox').children().remove();
                    $.each(response,function(i,v){
                        var $ul = $('<ul/>').addClass('item')
                        $ul.append('<li>'+v.ID+'</li>');
                        $ul.append('<li>'+v.Name+'</li>');
                        $ul.append('<li>'+v.County+'</li>');
                        $('.tablebox').append($ul);
                    })
                    ajaxing=0;//設定ajax處理結束
                },
                error:function(XMLHttpRequest, textStatus, errorThrown){
                    console.log(XMLHttpRequest.responseText);
                    ajaxing=0;//設定ajax處理結束
                }
            });
        }
    },1000);

japhenchen 的方式也是一種。不過他是有危險的。一但ajax發生任何請求問題。
就會停止了。這就得看方法使用了。

看更多先前的回應...收起先前的回應...

同意

我沒想划ajax fail的狀態,不然直接在.fail(或error)也加一個settimeout也是一個方法

其實我不用 settimeout 還有另一個因素啦。
就是還要再用一個function處理。

我是不太敢完全信賴js的變數,不過網頁有個特性,出錯了就停止往後的工作,免得一個錯誤引發更多的錯誤,但要做好一事,就是出錯時告知使用者,發生了什麼事

你的論點是對的,但這個論點是不該建立在ajax上的。
你說的變數問題,大多都是人為的因素。而不是程式本身的問題。
你並不能怪罪於它身上。

ajax本身是存在可能失敗的情況,且這個失敗來源並非來自程式且無法控制。這時工程師得要決定的是,要忽視這個運行,然後下次再運行。還是就直接停止運行。
這兩種情況,得視應用的運行來決定。並沒有一定性哪邊比較好及哪邊比較不好。

一切的決定在於工程師的身上,畢竟前端有個很大的問題。使用者並非是工程師。在某些情況下是不能回報任何錯誤給其它人知道。

我上面的寫法採用了

console.log(XMLHttpRequest.responseText); 

就是不將其直接顯示而回報於console上。
在這每秒請求的情況下。一般並不需要用alert之類的視窗。
這一秒拿不到,下一秒再拿就好。

當然,其實安全點我會用個時間計次。超過多久一直沒請求到的。我會將其計時器停止。但這已經是提外話了。

我要發表回答

立即登入回答