2017-07-09 32 views
0

當用戶離開我的web應用程序時,我需要向服務器發送一些數據。最好的方法是使用navigator.sendBeacon,但瀏覽器支持很差。我嘗試了同步ajax請求,但是我發現這是一個糟糕的做法 - 如果服務器沒有返回響應並且沒有辦法設置超時,那麼該選項卡將被凍結。所以我需要在所有瀏覽器上可靠地發送數據,而不會在服務器無法快速響應的情況下發生超時。在卸載時將ajax數據發送到服務器,並且超時

我已經實現了它,我要回答這個問題,但任何建議或其他解決方案都非常歡迎。

回答

0

好的,所以可以使用異步XHR和2個事件完成:beforeunload和unload。

我試圖在一個事件中完成它,但直到循環結束時纔會發送請求,即使請求是在循環之前發送的。

在beforeunload處理程序中,發送異步請求並保存當前時間。然後在卸載處理程序中,如果沒有足夠的時間或服務器響應(檢查readyState),則會放置一個while循環。 當循環結束時,瀏覽器可以自由卸載窗口。

這是代碼。如果瀏覽器支持,我也啓用發送信標。

var unloadRequest = null, 
     requestStartTime = null, 
     isBeaconSupported = (navigator && typeof navigator.sendBeacon === 'function'); 

    window.onbeforeunload = function() { 

    if (isBeaconSupported) { 

      unloadRequest = new XMLHttpRequest(); 
      unloadRequest.withCredentials = true; 
      unloadRequest.open('POST', '/beacon', true); 
      unloadRequest.setRequestHeader("Content-Type", "text/plain"); 

      requestStartTime = performance.now(); 
      unloadRequest.send(JSON.stringify({ test: true, _sentBy: 'XMLHttpRequest' })); 

    } 

    //return true; 

}; 

window.onunload = function() { 

    if (isBeaconSupported) { 

    navigator.sendBeacon('/beacon', JSON.stringify({ test: true, _sentBy: 'beacon' })) 

    } else if (unloadRequest) { 

    //continue the loop if time is left and the request havent finished 
    while (requestStartTime + 3000 > performance.now() && unloadRequest.readyState !== XMLHttpRequest.DONE) { 

     //console.log(unloadRequest.readyState); 

     } 

     console.log('request finished or timed out') 
     console.log('it took: ' + (performance.now() - requestStartTime) + 'ms'); 

    }   

}; 
相關問題