2015-12-17 8 views
11

La mia app Web utilizza il metodo 'long poll' per tenersi aggiornati con gli ultimi dati dal mio server. Il server risponde solo quando ha nuovi dati, che possono essere molti minuti a parte. (È un sistema di controllo del riscaldamento in cui si vedono solo gli aggiornamenti quando le temperature della stanza cambiano o qualcuno cambia le impostazioni).long-poll jQuery.ajax() non riesce a richiamare dopo il sonno del telefono?

var version = "0"; 
function updater() { 
    $.ajax({ 
     type: "POST", 
     url: "/listen", 
     data: version, 
     success: function (data) { 
      version = handleUpdates(data); 
      updater(); 
     }, 
     error: function() { 
      setTimeout(updater, 1000); 
     } 
    }); 
} 

Funziona benissimo su browser desktop e telefoni, tranne in un caso. Ho trovato che su telefoni Android con Chrome qualcosa di strano accade dopo che il telefono è andato a dormire per più di circa 10 minuti. La richiesta di posta sembra essere abbandonata, il che credo sia ragionevole dato che il telefono è addormentato. Nella scheda Rete del debugger di Chrome, il testo di stato della richiesta POST dice (annullato).

Il problema si verifica quando si riattiva il telefono mentre la richiesta viene annullata, né viene chiamata la funzione success() o error() e la mia app Web non viene mai aggiornata. $ .ajax() ha rotto la sua promessa per richiamarmi.

Il problema si verifica solo su alcuni dispositivi. Sono stato in grado di fare alcuni test ad hoc prendendo in prestito i dispositivi dagli amici. Finora ho visto solo il problema sui telefoni Android. Ma non è il telefono è collegato a un caricabatterie. Non l'ho visto su nessun tablet, su dispositivi Apple o PC Windows.

Ho provato ad aggiungere un timeout per le impostazioni di Ajax:

 timeout: 120 * 1000, 

Questo aiuta perché la funzione di errore() è infine chiamato fino a 2 minuti dopo il risveglio. Ma mi piacerebbe che l'utente vedesse gli aggiornamenti entro 1 o 2 secondi. Non voglio rendere il timeout così breve perché creerebbe traffico del server non necessario.

Ho anche provato a rilevare se il dispositivo è in sospensione cercando il ritardo in un secondo setInterval come descritto in Can any desktop browsers detect when the computer resumes from sleep?. Quando rilevo il risveglio, interrompo() il post e ne avvio un altro. Questo aiuta nella maggior parte dei casi. Ma risulta inaffidabile. A volte gli eventi del tempo sembrano mantenere il ticchettio normalmente durante il sonno e la richiesta di posta viene comunque cancellata. E non sembra una soluzione affidabile.

Sto usando l'ultima versione di jQuery: (2.1.2) e Chrome (47).

+0

provare a memorizzare la promessa corrente a livello globale, quindi quando si entra in questo stato fallito, controllare lo stato() della promessa. Cosa contiene? Se contiene qualcosa di diverso da "in sospeso", puoi usarlo combinato con la soluzione di @ spozun per riavviare le cose dopo un periodo di sospensione senza richieste di annullamento inutili. –

risposta

0

Non sicuro che questo funzionerà o meno, non posso provarlo ora, ma fare un tentativo problemi

$(window).focus(function() { 
    updater(); 
}); 
+0

Non fornirebbe un'altra richiesta nei casi in cui il browser funziona come previsto e lascia aperta la richiesta? – Katana314

+0

@ Katana314 questo si innesca solo se l'utente era in un'altra scheda (suppongo che funzioni anche inattivo sui dispositivi mobili) e che metta a fuoco la mia scheda. Ovviamente puoi anche usare qualche tipo di flag per vedere se l'updater funziona come previsto – Almis

+0

Purtroppo questo non funziona. Ci ha provato. $ (window) .focus() non chiama la funzione quando il telefono si risveglia dal sonno. Sembra solo chiamare la funzione quando si passa da una scheda all'altra in Chrome. – James

0

che ho avuto in passato con le chiamate sempre sospeso JavaScript quando il telefono va a dormire. La soluzione alla quale ho avuto a che fare è stata utilizzare window.setInterval() che sembra sospendere, ma tornare in vita quando il telefono viene svegliato.

Quindi suggerirei di impostare un intervallo che annulla la chiamata ogni tanto e lo reinizia. Questo potrebbe aiutare a sopravvivere attraverso il sonno del telefono.

Qualcosa di grosso modo così:

var myCall = $.ajax({...}); 

Window.setInterval (refreshCall(), 10000); 

function refreshCall(){ 
    myCall.abort(); 
    myCall = $.ajax({...}); 
} 
0

ne dite di una funzione di osservatore di livello superiore in questo modo:

var restartTimer = null; 
function updater(){ 
    $.ajax({ 
     type: "POST", 
     url: "/listen", 
     data: version, 
     success: function (data) { 
      version = handleUpdates(data); 
      clearTimeout(restartTimer); 
      updater(); 
     }, 
     error: function() { 
      clearTimeout(restartTimer); 
      setTimeout(updater, 1000); 
     } 
    }); 
} 
// Kick it when the phone wakes up. 
$(window).focus(function(){ 
    restartTimer = setTimeout(function(){ 
     initializeAll(); 
    }, 6000); 
    updater(); 
}); 

Voi sapete che il $ (window) .focus scatterà quando il telefono si sveglia , quindi prova updater() come suggerisce Almis, ma con un timer fail-safe.Se l'aggiornamento si attiva (su laptop o iOS), il timer viene annullato e tutto va bene, ma se l'aggiornamento è morto, il timer fail-safe scatta in 6 secondi e riavvia l'intera app chiamando initializeAll().

0

Che ne dici di un setInterval, che memorizza l'ora in cui è stato chiamato, quindi confronta l'ultima volta che è stato chiamato all'ora corrente - se l'intervallo è 10 secondi e il tempo trascorso dall'ultima esecuzione è stata di 5 minuti, è possibile supponi che ti sei appena svegliato dal sonno? Quindi interrompere la chiamata ajax corrente e riavviarla.

0

La risposta migliore è "non farlo". Stai aspettando che il server risponda mentre tiene traccia delle modifiche sul lato server. Basta che il server risponda e abbia il ping jQuery su un intervallo. È possibile includere ultimo o modificato se si desidera impedire effettivamente l'aggiornamento quando non c'è cambiamento di stato, ma se il server sta facendo lo stesso lavoro in ogni caso, lascia che risponda e attenda il prossimo sondaggio.

setInterval(function() { 
    $.post({"/listen", version, function (data) { 
     if(data.haschanged) 
      version = handleUpdates(data); 
    }).fail(function() { 
     // any error correction on failed call 
    }); 
}, 1000); 
Problemi correlati