Opisany problem jest dwojaki.
- Program, który piszesz, powinien zachowywać się asynchronicznie jako całość , patrząc z zewnątrz .
- W miejscu wywołania nie powinno być widoczne, czy wywołanie funkcji potencjalnie poddaje się kontroli, czy nie.
Jest kilka sposobów na osiągnięcie tego, ale w zasadzie sprowadzają się do
- posiadanie wielu wątków (na pewnym poziomie abstrakcji)
- posiadające wiele rodzajów funkcji na poziomie językowym, z których wszystkie są nazywane w ten sposób
foo(4, 7, bar, quux)
.
W przypadku (1) skupiam się na rozwidlaniu i uruchamianiu wielu procesów, spawnowaniu wielu wątków jądra i implementacjach zielonego wątku, które planują wątki poziomu języka wykonawczego na wątki jądra. Z punktu widzenia problemu są one takie same. Na tym świecie żadna funkcja nigdy się nie poddaje ani nie traci kontroli z perspektywy swojego wątku . Sam wątek czasami nie ma kontroli i czasem nie działa, ale nie rezygnujesz z kontroli nad własnym wątkiem na tym świecie. System pasujący do tego modelu może, ale nie musi, odradzać nowe wątki lub łączyć się z istniejącymi wątkami. System pasujący do tego modelu może, ale nie musi, mieć zdolność duplikowania wątku takiego jak Unix fork
.
(2) jest interesujące. Aby tego dokonać, musimy porozmawiać o formularzach wprowadzających i eliminujących.
Pokażę, dlaczego await
nie można dodać niejawnego do języka takiego jak Javascript w sposób zgodny z poprzednimi wersjami. Podstawową ideą jest to, że poprzez obnażanie obietnic użytkownikowi i rozróżnienie kontekstów synchronicznych i asynchronicznych, Javascript wyciekł ze szczegółami implementacji, które uniemożliwiają równomierne obsługiwanie funkcji synchronicznych i asynchronicznych. Istnieje również fakt, że nie można await
obiecać poza ciałem funkcji asynchronicznej. Te opcje projektowania są niezgodne z „powodowaniem, że asynchroniczność jest niewidoczna dla dzwoniącego”.
Możesz wprowadzić funkcję synchroniczną za pomocą lambda i wyeliminować ją za pomocą wywołania funkcji.
Wprowadzenie do funkcji synchronicznej:
((x) => {return x + x;})
Eliminacja funkcji synchronicznej:
f(4)
((x) => {return x + x;})(4)
Można to porównać z wprowadzaniem i eliminowaniem funkcji asynchronicznych.
Wprowadzenie do funkcji asynchronicznej
(async (x) => {return x + x;})
Eliminacja funkcji asynchronicznej (uwaga: obowiązuje tylko wewnątrz async
funkcji)
await (async (x) => {return x + x;})(4)
Podstawowym problemem jest to, że funkcja asynchroniczna jest również funkcją synchroniczną, która tworzy obiekt obietnicy .
Oto przykład wywoływania funkcji asynchronicznej synchronicznie w replie node.js.
> (async (x) => {return x + x;})(4)
Promise { 8 }
Możesz hipotetycznie mieć język, nawet dynamiczny, w którym różnica między wywołaniami funkcji asynchronicznej i synchronicznej nie jest widoczna w miejscu wywołania i prawdopodobnie nie jest widoczna w miejscu definicji.
Biorąc taki język i obniżając go do Javascript jest możliwe, po prostu trzeba by skutecznie sprawić, by wszystkie funkcje były asynchroniczne.