O problema que você está descrevendo é duplo.
- O programa que você está escrevendo deve se comportar de maneira assíncrona como um todo, quando visto de fora .
- Ele deve não ser visível no site da chamada se uma chamada de função potencialmente dá o controle ou não.
Existem algumas maneiras de conseguir isso, mas elas basicamente se resumem a
- tendo vários threads (em algum nível de abstração)
- tendo vários tipos de função no nível do idioma, todos chamados assim
foo(4, 7, bar, quux)
.
Para (1), estou reunindo bifurcação e execução de vários processos, gerando vários threads do kernel e implementações de threads verdes que agendam threads do nível de tempo de execução da linguagem nos threads do kernel. Da perspectiva do problema, eles são os mesmos. Neste mundo, nenhuma função desiste ou perde o controle da perspectiva de seu segmento . O fio em si , por vezes, não tem controle e às vezes não está em execução, mas você não desista controle de seu próprio segmento no mundo. Um sistema adequado a este modelo pode ou não ter a capacidade de gerar novos threads ou ingressar em threads existentes. Um sistema adequado a este modelo pode ou não ter a capacidade de duplicar um thread como o do Unix fork
.
(2) é interessante. Para fazer justiça, precisamos falar sobre formas de introdução e eliminação.
Vou mostrar por que o implícito await
não pode ser adicionado a uma linguagem como Javascript de uma maneira compatível com versões anteriores. A idéia básica é que, expondo promessas ao usuário e fazendo uma distinção entre contextos síncronos e assíncronos, o Javascript vazou um detalhe de implementação que impede o tratamento uniforme de funções síncronas e assíncronas. Há também o fato de que você não pode fazer await
uma promessa fora de um corpo de função assíncrona. Essas opções de design são incompatíveis com "tornar a assincronia invisível para o chamador".
Você pode introduzir uma função síncrona usando um lambda e eliminá-lo com uma chamada de função.
Introdução da função síncrona:
((x) => {return x + x;})
Eliminação da função síncrona:
f(4)
((x) => {return x + x;})(4)
Você pode contrastar isso com a introdução e eliminação de funções assíncronas.
Introdução à função assíncrona
(async (x) => {return x + x;})
Eliminação de função assíncrona (nota: válida apenas dentro de uma async
função)
await (async (x) => {return x + x;})(4)
O problema fundamental aqui é que uma função assíncrona também é uma função síncrona que produz um objeto de promessa .
Aqui está um exemplo de chamada de uma função assíncrona de forma síncrona no repl do node.js.
> (async (x) => {return x + x;})(4)
Promise { 8 }
Hipóteses, você pode ter um idioma, mesmo que digitado dinamicamente, em que a diferença entre as chamadas de função assíncrona e síncrona não seja visível no site da chamada e possivelmente não seja visível no site da definição.
É possível usar uma linguagem como essa e reduzi-la para Javascript, você apenas precisa efetivamente tornar todas as funções assíncronas.