1. 程式人生 > >瀏覽器重新整理頁面/關閉頁面時,使用jquery+ajax儲存資料的方法

瀏覽器重新整理頁面/關閉頁面時,使用jquery+ajax儲存資料的方法

最近做個人專案的時候,有一個需求:使用者在頁面進行各種編輯操作,但是卻不必顯示的儲存修改,下次開啟頁面時依然可以看到修改後的內容。
看到這個需求第一反應就是,前端無感知,後端自動儲存修改。具體怎麼做呢?我的思路是:
1、在前端有修改時,寫一個jquery函式(命名為:storeChange)——通過ajax將修改的內容傳輸到後端,由後端進行操作,比如儲存資料庫等。下次訪問時,從資料庫讀取資料。
2、為了防止使用者在重新整理/關閉頁面不丟失資料,因此需要通過jquery在這兩個事件的時候呼叫storeChange函式。

第一個版本程式碼如下:

//頁面關閉時呼叫
$(window).unload(function
() {
storeChange(); }); //頁面重新整理時呼叫 $(window).on('beforeunload', function(event) { storeChange(); }); //前端頁面內容修改觸發 function haveModified() { //做一些事情 storeChange(); } function storeChange() { //做一些事情 $.ajax({ type:"POST", dataType:"json", data:{projectId:projectId,projectLists:arrProjectNodes}, url:'Project/Project/modifyProject'
, success:function (data) { if (data.errno == 0) { //do something } else { console.log('there are some errors in project.js:storeChange ajax' + data.errno + ': ' + data.msg); } }, error:function (er) { console.log('some error in project.js:storeChange ajax'
); } }); }

但是經檢驗這個版本有諸多問題:
第一、也是最嚴重的就是在重新整理和關閉頁面的時候,經常丟失資料(chrome)甚至部分瀏覽器完全不起作用(遨遊-極速模式,相容模式未試,這裡不是黑遨遊瀏覽器,本人是遨遊瀏覽器的忠實使用者,從初中用到現在,十多年了,個人感覺還是非常好用的);
第二、如果操作非常頻繁,會頻繁呼叫後端介面,浪費資源、加大後端壓力。

因此針對這兩個問題進行解決,方案如下:
針對第一個問題:
【原因】
由於ajax預設是非同步呼叫,這樣就有一個問題:document的內容是先被銷燬,還是先被傳輸到後端?如果是後者則符合專案需求,而如果是前者就會出現問題。
【解決方案】
將重新整理和關閉頁面時呼叫的storeChange函式中的ajax改為同步方式。

針對第二個問題:
【原因】
每一個修改(會點選一些按鈕等進行新增、刪除、編輯等)意味著監聽修改的函式都會被呼叫。
【解決方案(前端)】
設定定時器,預設每過10秒呼叫一次storeChange函式來非同步請求後端介面,這樣可以減少請求次數,而且對於覆蓋型(後面的修改會將前面的修改覆蓋掉,實際上只儲存後面的修改即可)的編輯,效果最好。
【解決方案(後端)】
這裡就不具體討論後端的解決方案了,大體思路就是快取/訊息佇列等。本文只看前端解決方案。
【具體實現】
上述前端的解決方案並不完整,單純使用定時器不能滿足我們的需求,因為多次修改(10秒內)會產生多個定時器,因此需要設定一個cookie來記錄是否被修改,如果被修改,清除上一次的定時器,重新計時。(提醒,使用cookie需要引入jquery對應的檔案)

針對以上兩個問題,修改後的程式碼如下:

//頁面關閉時呼叫
$(window).unload(function()
{
    storeChangeRealTime();
});

//頁面重新整理時呼叫
$(window).on('beforeunload', function(event) {
    storeChangeRealTime();
});

//前端頁面內容修改觸發
var timerId = null;//記錄定時器名稱
function haveModified()
{
    //做一些事情
    $.cookie('projectlist_modify_flag', 1);//重新設定cookie,1表示:有修改
    //定時器
    clearTimeout(timerId);//清除之前的定時器(為了重新計時,否則會有多個定時器同時進行,傳遞多次資料)
    timerId = setTimeout(storeChangeDelay, 10000);//設定定時器
} 

function storeChangeDelay()
{
    //做一些事情

    $.ajax({
        type:"POST",
        dataType:"json",
        data:{projectId:projectId,projectLists:arrProjectNodes},
        url:'Project/Project/modifyProject',
        success:function (data) {
            if (data.errno == 0) {
                $.cookie('projectlist_modify_flag', 0);//修改的內容已經儲存,將該cookie置為0
            } else {
                console.log('there are some errors in project.js:storeChange ajax' + data.errno + ': ' + data.msg);
            }
        },
        error:function (er) {
            console.log('some error in project.js:storeChange ajax');
        }
    });
}

function storeChangeRealTime()
{
    //做一些事情

    $.ajax({
        async:false,//這是與storeChangeDelay不同的地方,表示使用同步方式傳輸資料
        type:"POST",
        dataType:"json",
        data:{projectId:projectId,projectLists:arrProjectNodes},
        url:'Project/Project/modifyProject',
        success:function (data) {
            if (data.errno == 0) {
                $.cookie('projectlist_modify_flag', 0);//修改的內容已經儲存,將該cookie置為0
            } else {
                console.log('there are some errors in project.js:storeChange ajax' + data.errno + ': ' + data.msg);
            }
        },
        error:function (er) {
            console.log('some error in project.js:storeChange ajax');
        }
    });
}

程式碼是精簡過的,只是提供個解決這類問題的思路。

PS:當然,這種方法還是有弊端的,比如在重新整理頁面時,由於使用的是ajax同步方式,因此資料量過大或連線慢的話,可能會造成卡頓、甚至假死。如有更好方法請告知,將不勝感激。

水平有限,歡迎指正~
如需轉發,請註明出處,3q~