Il problema che stai descrivendo è duplice.
- Il programma che stai scrivendo dovrebbe comportarsi in modo asincrono nel suo insieme se visto dall'esterno .
- Dovrebbe non essere visibile sul sito chiamata se una chiamata di funzione fornisce potenzialmente il controllo o meno.
Ci sono un paio di modi per raggiungere questo obiettivo, ma sostanzialmente si riducono a
- avere più thread (a un certo livello di astrazione)
- avere più tipi di funzioni a livello linguistico, tutte chiamate in questo modo
foo(4, 7, bar, quux)
.
Per (1), sto raggruppando insieme il fork e l'esecuzione di più processi, generando più thread del kernel e implementazioni di thread verdi che pianificano thread a livello di runtime di linguaggio sui thread del kernel. Dal punto di vista del problema, sono gli stessi. In questo mondo, nessuna funzione si arrende mai o perde il controllo dalla prospettiva del suo thread . Il thread stesso a volte non ha controllo e talvolta non è in esecuzione ma non si rinuncia al controllo del proprio thread in questo mondo. Un sistema adatto a questo modello può avere o meno la possibilità di generare nuovi thread o unirsi a thread esistenti. Un sistema adatto a questo modello può avere o meno la possibilità di duplicare un thread come quello di Unix fork
.
(2) è interessante. Per rendere giustizia dobbiamo parlare di moduli di introduzione ed eliminazione.
Mostrerò perché await
non è possibile aggiungere implicito a una lingua come Javascript in modo compatibile con le versioni precedenti. L'idea di base è che esponendo le promesse all'utente e distinguendo tra contesti sincroni e asincroni, Javascript ha fatto trapelare un dettaglio di implementazione che impedisce la gestione uniforme delle funzioni sincrone e asincrone. C'è anche il fatto che non puoi await
promettere al di fuori di un corpo di funzione asincrono. Queste scelte progettuali sono incompatibili con "rendere invisibile l'asincrono al chiamante".
È possibile introdurre una funzione sincrona utilizzando una lambda ed eliminarla con una chiamata di funzione.
Introduzione alla funzione sincrona:
((x) => {return x + x;})
Eliminazione della funzione sincrona:
f(4)
((x) => {return x + x;})(4)
È possibile contrastare questo con l'introduzione e l'eliminazione della funzione asincrona.
Introduzione alla funzione asincrona
(async (x) => {return x + x;})
Eliminazione della funzione asincrona (nota: valida solo all'interno di una async
funzione)
await (async (x) => {return x + x;})(4)
Il problema fondamentale qui è che una funzione asincrona è anche una funzione sincrona che produce un oggetto promessa .
Ecco un esempio di come chiamare una funzione asincrona in modo sincrono nella sostituzione node.js.
> (async (x) => {return x + x;})(4)
Promise { 8 }
È possibile ipotizzare un linguaggio, anche se digitato in modo dinamico, in cui la differenza tra chiamate di funzione asincrone e sincrone non è visibile nel sito di chiamata e probabilmente non è visibile nel sito di definizione.
Prendendo una lingua del genere e abbassandola a Javascript è possibile, dovresti semplicemente rendere tutte le funzioni asincrone.