2012-07-02 12 views
11

Mam następujące zapytanie w jquery. Jest to odczyt adresu "publikuj" pary subskrypcji/publikacji Nginx skonfigurowanej przy użyciu modułu Long Polling Nginx.Chrome nie obsługuje kwerendy ajax jquery

function requestNextBroadcast() { 
     // never stops - every reply triggers next. 
     // and silent errors restart via long timeout. 
     getxhr = $.ajax({ 
      url: "/activity", 
      // dataType: 'json', 
      data: "id="+channel, 
      timeout: 46000, // must be longer than max heartbeat to only trigger after silent error. 
      error: function(jqXHR, textStatus, errorThrown) { 
       alert("Background failed "+textStatus); // should never happen 
       getxhr.abort(); 
       requestNextBroadcast(); // try again 
      }, 
      success: function(reply, textStatus, jqXHR) { 
       handleRequest(reply); // this is the normal result. 
       requestNextBroadcast(); 
      } 
     }); 
    } 

Kod jest częścią pokoju rozmów. Na każdą wysłaną wiadomość odpowiada odpowiedź zerowa (z 200/OK), ale dane są publikowane. To jest kod do odczytu adresu subskrypcji, gdy dane wracają.

Korzystanie z limitu czasu wszystkie osoby na czacie wysyłają prostą wiadomość co 30 do 40 sekund, nawet jeśli nic nie wpisują, więc istnieje wiele danych do przeczytania tego kodu - co najmniej 2 i być może więcej wiadomości na 40 sekund.

Kod jest w 100% skalny w wersjach EI i Firefox. Ale jeden czytany w około 5 nie działa w Chrome.

Gdy Chrome zawiedzie, obowiązuje limit czasu wynoszący 46 sekund.

Dziennik pokazuje jedno/nieaktualne żądanie sieci działania w tym samym czasie.

Przez trzy dni indeksowałem ten kod, próbując różnych pomysłów. I za każdym razem, gdy IE i Firefox działają dobrze, a Chrome zawiedzie.

Jedną z sugestii, którą widziałem, jest wykonanie synchronizacji połączenia - ale jest to oczywiście niemożliwe, ponieważ zablokowałoby to interfejs użytkownika zbyt długo.

Edit - Mam częściowe rozwiązanie: Kod jest teraz ten

function requestNextBroadcast() { 
    // never stops - every reply triggers next. 
    // and silent errors restart via long timeout. 
    getxhr = jQuery.ajax({ 
     url: "/activity", 
     // dataType: 'json', 
     data: "id="+channel, 
     timeout: <?php echo $delay; ?>, 
     error: function(jqXHR, textStatus, errorThrown) { 
      window.status="GET error "+textStatus; 
      setTimeout(requestNextBroadcast,20); // try again 
     }, 
     success: function(reply, textStatus, jqXHR) { 
      handleRequest(reply); // this is the normal result. 
      setTimeout(requestNextBroadcast,20); 
     } 
    }); 
} 

Wynik jest czasem odpowiedź jest opóźniona aż opóźnienie $ (15000) dzieje, to w kolejce wiadomości przybyć zbyt quicly do naśladowania. Nie byłem w stanie zrobić tego komunikatu (tylko testowane z wyłączoną opcją netwrok) z tą nową aranżacją.

Bardzo wątpię, że opóźnienia są trudne do problemów z siecią - wszystkie maszyny są maszynami wirtualnymi w mojej prawdziwej maszynie i nie ma innych użytkowników mojej lokalnej sieci LAN.

Edytuj 2 (piątek 2:30 BST) - Zmieniono kod, aby użyć obietnic - a POST działań zaczął pokazywać te same objawy, ale strona odbierająca zaczęła działać poprawnie! (???? !!! ???). To jest procedura POST - obsługuje ona sekwencję żądań, aby zapewnić, że tylko jedna z nich jest wyjątkowa.

function issuePostNow() { 
    // reset heartbeat to dropout to send setTyping(false) in 30 to 40 seconds. 
    clearTimeout(dropoutat); 
    dropoutat = setTimeout(function() {sendTyping(false);}, 
          30000 + 10000*Math.random()); 
    // and do send 
    var url = "handlechat.php?"; 
    if (postQueue.length > 0) { 
     postData = postQueue[0]; 
     var postxhr = jQuery.ajax({ 
      type: 'POST', 
      url: url, 
      data: postData, 
      timeout: 5000 
     }) 
     postxhr.done(function(txt){ 
      postQueue.shift(); // remove this task 
      if ((txt != null) && (txt.length > 0)) { 
       alert("Error: unexpected post reply of: "+txt) 
      } 
      issuePostNow(); 
     }); 
     postxhr.fail(function(){ 
      alert(window.status="POST error "+postxhr.statusText); 
      issuePostNow(); 
     }); 
    } 
} 

Około jedna akcja w 8 Wezwanie do handlechat.php będzie limitu czasu i pojawia się alarm. Po zakończeniu alertu przychodzą wszystkie oczekujące wiadomości w kolejce.

Zauważyłem także, że wywołanie handlechat zostało zatrzymane zanim napisało wiadomość, którą inni zobaczą. Zastanawiam się, czy to może być jakiś dziwny sposób obsługi danych sesji przez php. Wiem, że ostrożnie ustawia kolejki połączeń tak, aby dane sesji nie były uszkodzone, więc starałem się używać różnych przeglądarek lub różnych maszyn. Są tylko 2 wątki robocze PHP, jednak php NIE jest używany w obsłudze/activity lub w obsłudze zawartości statycznej.

Myślałem również, że może to być niedobór pracowników nginx lub procesorów php, więc podniosłem je. Obecnie trudniej jest doprowadzić do niepowodzenia, ale nadal możliwe. Domyślam się, że wywołanie funkcji/activity kończy się niepowodzeniem jeden raz na 30 razy i nie powoduje utraty komunikatów.

Dzięki chłopaki za twój wkład.


Podsumowanie ustaleń.

1) Jest to błąd w Chrome, który był przez jakiś czas w kodzie.
2) Przy odrobinie szczęścia błąd może zostać wyświetlony jako POST, który nie jest wysyłany, a po przekroczeniu czasu pozostawia Chrome w takim stanie, że powtórzony test POST zakończy się pomyślnie.
3) Zmienna używana do przechowywania zwrotu z $ .ajax() może być lokalna lub globalna. Nowe (obietnice) i stare wywołania formatów powodują błąd.
4) Nie znalazłem pracy ani sposobu na uniknięcie błędu.

Ian

+1

Jeśli podejrzewasz, że jest to problem z Chrome, może pomóc innym użytkownikom dowiedzieć się, z której wersji korzystasz. również wersja jQuery. – merv

+0

Chrome 20.0.1132.47 m jquery 1.7.2 O/S 64-bitowe okna na kliencie i Ubuntu 11:04 na serwerze. – Ian

+0

Testowałem to w Safari (5.1.7) i odkryłem, że działa. WIĘC to nie jest problem związany z Webkitem. Próbowano również w wersji 20.0.1132.47 Chrome na Linuksa i to jest problem. – Ian

Odpowiedz

2

spróbuj przenieść swoją funkcję odpytywania w WebWorker aby zapobiec zamarzaniu w chromie. W przeciwnym razie możesz spróbować użyć athe ajax .done() obiektu jquery. ten zawsze działa dla mnie w chromie.

+0

Dzięki Michael. Webworker jest niepraktyczny - muszę wspierać IE - i niepotrzebne, ponieważ nic, co robię, nie trwa długo. Problem polega nie na tym, że sukces() nie jest wywoływany, a jego odczyt nie kończy się NAWET JEŚLI ZNAJDUJE SIĘ ZNANE DANE.Krótko mówiąc, sukces można nazwać nawet 8 sekund później niż dane stały się dostępne. Sprawdzę done() i dam ci znać. – Ian

+0

Myślałem, że robisz przeglądarkę, jeśli jej chrome, aktywuj webworker, który wykonuje synchroniczne wywołanie. w ten sposób możesz mieć poprawkę dla chrome, ponieważ tylko chrome daje problemy. Muszę pokochać różnice w przeglądarce. Mam nadzieję, że rozwiązanie .done zadziała dla ciebie. To najłatwiejsze wdrożenie yo. – Tschallacka

0

Mam ochotę getxhr powinien być poprzedzony prefiksem "var". Czy nie chcesz zupełnie nowego, odrębnego żądania za każdym razem, a nie nadpisywania starego w trakcie zarządzania sukcesem/niepowodzeniem? Mogłoby wyjaśnić, dlaczego zachowanie "poprawia się" po dodaniu setTimeout. I może być również czegoś brakuje;)

+0

getxhr ma charakter globalny, a ja nie piszę go zbyt długo, dopóki nie skończę, więc mimo że mogę zrobić to lokalnie, nie widzę różnicy. Zastanawiałem się, czy Chrome nie czekał w kolejce na operację oczyszczania, którą wykonano przed ponownym wysłaniem. – Ian

+0

Mówisz, ale twój kod mówi, że piszesz go za każdym razem, gdy wywoływana jest funkcja requestNextBroadcast. To może być ok - potem, rzadko nawet używam wartości zwracanej z $ .ajax – shovemedia

0

Komentarze nie będzie format kodu, więc przeksięgowanie jako 2nd odpowiedź:

myślę Michael Dibbets jest na coś z $ .ajax.done - Odroczony wzór pcha przetwarzanie do następnego zwrotu pętli zdarzeń, co moim zdaniem jest zachowaniem, które jest tutaj potrzebne. patrz: http://www.bitstorm.org/weblog/2012-1/Deferred_and_promise_in_jQuery.html lub http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/

chciałbym spróbować czegoś takiego:

function requestNextBroadcast() { 
    // never stops - every reply triggers next. 
    // and silent errors restart via long timeout. 

    getxhr = jQuery.ajax({ 
    url: "/activity", 
    // dataType: 'json', 
    data: "id="+channel, 
    timeout: <?php echo $delay; ?> 
    }); 

    getxhr.done(function(reply){ 
    handleRequest(reply); 
    }); 

    getxhr.fail(function(e){ 
    window.status="GET error " + e; 
    }); 

    getxhr.always(function(){ 
    requestNextBroadcast(); 
    }); 

Uwaga: Mam trudności ze znalezieniem dokumentacji na argumentach zwrotnych dla Promise.done & Promise.fail :(

+0

Dlaczego nie daisz swoich wydarzeń? W ten sposób wszystkie zdarzenia zwrotne są wstrzykiwane z opóźnieniem. Teraz masz plik RIS, który pobiera ajax, zanim zostanie przydzielony pełny moduł obsługi i niedopasowanie procesów. – Tschallacka

+0

* bardzo * mało prawdopodobne, ale dobre złapanie! – shovemedia

+0

Wiem ... ale po tym, jak zobaczyłem, że Internet rośnie od IE4 i netscape nic już mnie nie zaskakuje ... Widziałem jak najbardziej niemożliwe rzeczy działają (na przykład tj. I zoom: 1 rzecz). Jeśli to nie działa w jedną stronę, to może w inny sposób, a Somethimes trzeba zrobić coś niemożliwego do osiągnięcia somthing ... różnice przeglądarce Kto ich nie lubią. – Tschallacka

0

może to być obejść zmieniając ustawienia modułu Push (istnieje kilka) - mógłbyś pisać te

z mojej głowie:

?
  • ustawienie go na interwał sondowania, by trochę uglily go rozwiązać
  • ustawienia współbieżności może mieć pewien wpływ
  • wiadomość przechowywania może być stosowany w celu uniknięcia brakujących danych

Chciałbym również użyć czegoś podobnego Charles, aby zobaczyć, co dokładnie dzieje się w sieci/warstwach aplikacji

4

Miałem bardzo podobny problem z Chrome. Wykonuję połączenie Ajax, aby uzyskać czas z serwera co sekundę. Oczywiście połączenie Ajax musi być asynchroniczne, ponieważ spowoduje zawieszenie interfejsu na timeoutie, jeśli nie jest. Ale gdy jeden z wywołań Ajax jest niepowodzeniem, każdy kolejny jest również. Najpierw próbowałem ustawić limit czasu na 100ms i to działało dobrze w IE i FF, ale nie w Chrome.Moim najlepszym rozwiązaniem było ustawienie typu POST i że rozwiązał problem z chromem dla mnie:

setInterval(function(){ 
     $.ajax({ 
     url: 'getTime.php', 
     type: 'POST', 
     async: true, 
     timeout: 100, 
     success: function() { console.log("success"); }, 
     error: function() { console.log("error"); } 
     }); 
    }, 1000); 

Aktualizacja: wierzę rzeczywista Podstawowym problemem jest tutaj sposób Chrome buforowania. Wygląda na to, że gdy jedno żądanie się nie powiedzie, ta awaria zostanie zapisana w pamięci podręcznej, a zatem kolejne żądania nie zostaną wykonane, ponieważ Chrome otrzyma buforowaną awarię przed zainicjowaniem kolejnych żądań. Można to zobaczyć, przechodząc do narzędzi programistycznych Chrome i przechodząc do karty Sieć, i sprawdzając, jakie żądania zostały wysłane. Przed niepowodzeniem żądania ajax do getTime.php są wykonywane co sekundę, ale po 1 awarii kolejne żądania nigdy nie są inicjowane. Dlatego następujące rozwiązanie pracował dla mnie:

setInterval(function(){ 
     $.ajax({ 
     url: 'getTime.php', 
     cache: false, 
     async: true, 
     timeout: 100, 
     success: function() { console.log("success"); }, 
     error: function() { console.log("error"); } 
     }); 
    }, 1000); 

Zmiana tutaj jest ja wyłączenie buforowania do tego zapytania Ajax, ale w tym celu, opcja typ musi być albo GET lub HEAD, dlatego usunięto "type: 'POST'" (domyślnie GET).

Powiązane problemy