Czy asynchronizacja w przeglądarce jest naprawdę nieblokująca?

Bawiłem się tą funkcją w SPA używając maszynopisu i natywnych obietnic i zauważyłem, że nawet jeśli zmienię długo działającą funkcję w funkcję asynchroniczną zwracającą obietnicę, interfejs nadal nie odpowiada.

Więc moje pytania to:

  • W jaki sposób nowa funkcja async / wait pomaga uniknąć blokowania interfejsu użytkownika w przeglądarce? Czy są jakieś specjalne dodatkowe kroki, które należy podjąć podczas korzystania z asynchronicznego / oczekującego, aby rzeczywiście uzyskać responsywny UI?

  • Czy ktoś może stworzyć fiddle, aby zademonstrować jak async / wait pomaga uczynić interfejs responsywnym?

  • Jak async / wait ma się do wcześniejszych funkcji async, takich jak setTimeout i XmlHttpRequest?

Author: Felix Kling, 2017-03-14

3 answers

await p planuje wykonanie reszty funkcji po rozwiązaniu promise p. To wszystko.

async pozwala na użycie await. To (prawie) wszystko, co robi (to również owija Twój wynik w obietnicę).

Razem sprawiają, że kod nieblokujący czyta się jak prostszy kod blokujący. Nie odblokowują kodu.

Aby uzyskać responsywny interfejs użytkownika, odciążaj pracę CPU do wątku worker i przesyłaj do niego wiadomości:

async function brutePrime(n) {
  function work({data}) {
    while (true) {
      let d = 2;
      for (; d < data; d++) {
        if (data % d == 0) break;
      }
      if (d == data) return self.postMessage(data);
      data++;
    }
  }

  let b = new Blob(["onmessage =" + work.toString()], {type: "text/javascript"});
  let worker = new Worker(URL.createObjectURL(b));
  worker.postMessage(n); 
  return await new Promise(resolve => worker.onmessage = e => resolve(e.data));
}

(async () => {
  let n = 700000000;
  for (let i = 0; i < 10; i++) {
    console.log(n = await brutePrime(n + 1));
  }
})().catch(e => console.log(e));
 33
Author: jib,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-17 01:38:49

async jest bardziej eleganckim sposobem na strukturę kodu asynchronicznego. Nie pozwala na żadne nowe możliwości; to po prostu lepsza składnia niż wywołania zwrotne lub obietnice.

Więc async nie można użyć do "stworzenia czegoś asynchronicznego". Jeśli masz kod, który musi wykonywać wiele procesów opartych na CPU, async nie będzie magicznie reagować interfejs użytkownika. To, co musisz zrobić, to użyć czegoś w rodzaju web workers , które właściwym narzędziem do pchania pracy związanej z CPU do wątku w tle w aby interfejs był responsywny.

 10
Author: Stephen Cleary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-14 02:03:11

JavaScript jest jednowątkowy i działa w tym samym wątku co interfejs użytkownika. Więc cały kod JavaScript zablokuje interfejs użytkownika. Jak wspomniano przez innych pracowników sieci mogą być używane do uruchamiania kodu w innych wątkach, ale mają ograniczenia.

Różnica między funkcjami asynchronicznymi a regularnymi polega na tym, że zwracają one obietnicę. Za pomocą wywołania zwrotnego można następnie odroczyć wykonanie kodu, który obsługuje wynik wywołania funkcji, a tym samym pozwala UI wykonać pewną pracę. Następujące trzy przykłady mają ten sam efekt:

async function foo() {
  console.log("hi");
  return 1; 
}
foo().then(result => console.log(result))
console.log("lo");

function foo() {
  console.log("hi");
  return 1; 
}
Promise.resolve(foo()).then(result => console.log(result))
console.log("lo");

function foo() {
  console.log("hi");
  return 1; 
}
const result = foo();
setTimeout(() => console.log(result));
console.log("lo");

We wszystkich trzech przypadkach konsola rejestruje hi, lo, 1. Przed wydrukowaniem 1 interfejs użytkownika może obsługiwać wprowadzanie danych przez użytkownika lub rysowanie aktualizacji. Powodem 1, który jest drukowany jako ostatni w dwóch pierwszych przypadkach, jest to, że wywołania zwrotne dla obietnic nie są wykonywane natychmiast.

await pozwala to zrobić bez wywołania zwrotnego:

async function foo() {
  console.log("hi");
  return 1; 
}

async function bar() {
  const result = await foo();
  console.log(result);
}

bar();
console.log("lo"); 

To również wydrukuje hi, lo, 1. Podobnie jak wywołanie zwrotne dla obietnicy, kod po await nigdy nie jest wykonywany od razu.

 5
Author: a better oliver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-16 12:11:48