Web Worker bloqué par thread principal dans Chrome

J'ai un travailleur Web . Je souhaite faire périodiquement des demandes de réseau. Une chose que je souhaite particulièrement est de faire ces demandes même si le thread d'exécution JS principal est bloqué (par exemple, par un window.alert). J'aime Chrome 38.

Cependant, lorsque j'essaie de faire des requêtes réseau dans le travailleur, les requêtes semblent bloquées par le thread UI. Voici un exemple conçu pour illustrer le problème:

Base.js:

var worker = new Worker("/worker.js"); setTimeout(function() { console.log("begin blocking"); var startDt = new Date(); var blockPeriod = 5000; var a; // Obviously we'd never actually do this, but this while loop // is a convenient way to create the problem case (a blocked main // thread). while ((new Date() - startDt) < blockPeriod) { a = 0; } console.log("stop blocking"); }, 3000); 

Worker.js:

 var requestInterval = 1000; var sendRequest = function() { console.log("Send request interval"); var request = new XMLHttpRequest(); request.open("GET", "/ping", true); request.onload = function() { if (request.status === 200){ console.log(request.responseText) } else { console.log(request.status) } }; request.onerror = function() { console.log("error") }; request.send(); setTimeout(sendRequest, requestInterval); } sendRequest(); 

Le résultat que je vois est que nous voyons des requêtes HTTP réussies pendant trois secondes, jusqu'à ce que le blocage commence. À ce stade, nous ne voyons rien sur la console jusqu'à ce que le blocage se termine, auquel cas nous voyons cinq "Intervalles d'envoi" suivi de 5 logs de la réponse, ainsi:

 Send request interval {"pong": true} Send request interval {"pong": true} Send request interval {"pong": true} Send request interval {"pong": true} begin blocking stop blocking 5x Send request interval 5x {"pong": true} Send request interval {"pong": true} 

Je vois également dans mes journaux de serveur qu'aucune demande n'est faite dans ce temps de blocage, alors ces cinq requêtes sont toutes reçues à peu près simultanément à la fin de la période de blocage.

Étant donné que "l'intervalle de demande d'envoi" se produit cinq fois de suite, le travailleur continue évidemment à s'exécuter: si ce n'était pas le cas, il ne serait pas nécessaire de mettre en file d'attente la prochaine itération. J'ai également constaté que si je bloque en déclenchant une fenêtre.alert au lieu de tourner en boucle, j'obtiens les messages de journal depuis le début de sendRequest à des intervalles de 1 seconde, puis obtenez les messages de journal du gestionnaire de réponse dans un grand lot comme Dès que j'arrête de bloquer.

Dans Firefox, le thread d'arrière-plan semble s'arrêter entièrement dans ce cas (je n'obtient pas le même lot de cinq requêtes en attente pendant la période bloquée). Cependant, je ne vise que Chrome dans ce cas (et je souhaite finalement utiliser WebSockets qui ne fonctionnent même pas dans Firefox Workers), donc je ne m'intéresse vraiment pas à cela.

Tous ajoutés, cela m'amène à croire qu'il existe certaines classes d'activités dans les Web Workers qui sont bloquées par le fil de fraie, et certaines qui ne le sont pas (j'ai d'abord vu ce même comportement avec WebSockets). Concrètement, j'aimerais savoir (si quelqu'un le sait):

  1. Quelle est l'activité du travailleur bloquée par le thread principal dans Chrome?
  2. Existe-t-il un moyen de contourner cela? J'aimerais beaucoup pouvoir établir une connexion WebSocket dans un Worker, puis continuer à PING / PONG d'avant en arrière, même si quelque chose (comme une alerte / confirmation) bloque le thread principal.
  3. Est-ce que c'est une absurdité, et est-ce que je fais quelque chose de stupide?

Votre observation est correcte. Lorsque le thread UI est bloqué, les appels réseau ne sont pas envoyés.

Pire encore, Chrome a le meilleur comportement du groupe. Lorsqu'un travailleur effectue une requête XHR lorsque le thread UI est bloqué:

  • Chrome: toutes les demandes sont mises en file d'attente. Le navigateur n'émettra pas les requêtes avant que le thread UI ne soit bloqué. Sur le côté positif, le thread du travailleur est toujours libre de fonctionner.
  • Firefox: new XMLHttpRequest() blocs new XMLHttpRequest() jusqu'à ce que le thread UI débloque.
  • IE: xhr.open() blocs jusqu'à ce que le thread UI débloque.

Bien que Chrome n'attire heureusement pas qu'un thread de travail s'arrête et attend (même s'il n'obtient aucune donnée), Firefox et IE provoqueront un thread de travail sur le thread UI lorsque vous essayez de faire une demande XHR.

Il n'y a aucun moyen de contourner cela; Vous êtes redevable du navigateur pour faire des demandes en votre nom. Je n'ai effectué aucun test avec WebSockets, mais ils peuvent fournir des événements même si le thread UI est bloqué. Au pire, les messages reçus faisaient la queue jusqu'à ce que le thread UI se débloque.

Dans le cas où quelqu'un trébuchait à travers cela, ce comportement est confirmé comme un bogue (à la définition lâche de "bug" que "ne se comporte pas comme il se doit") à Blink, en février 2015:

https://code.google.com/p/chromium/issues/detail?id=443374