I termini asincroni e paralleli sono spesso scambiati, sebbene asincroni significhi che qualcosa fuori banda accade in relazione al flusso principale di esecuzione (interrompendo quindi il flusso principale di esecuzione), spesso questa interruzione può essere in servizio di un I / O routine di completamento. Pertanto, async implica un'interruzione (potenzialmente arbitrariamente temporizzata) del thread principale e non necessariamente un secondo thread completo. Su alcuni sistemi (ma non su JavaScript), il thread principale viene temporaneamente sospeso e quindi con jack alto per servire la routine di completamento dell'I / O (quindi il lavoro sospeso viene ripreso).
Mentre parallelamente due o più cose (discussioni) avvengono simultaneamente. Su un uniprocessore non esiste una vera esecuzione parallela; tuttavia, viene simulato interrompendo qualsiasi thread attualmente in esecuzione (e spesso in un punto arbitrario) per dare un po 'di tempo CPU ad un altro thread. Sui sistemi a multiprocessore, ci sarà sia l'esecuzione simultanea di diverse CPU, sia l'interruzione ai fini dell'esecuzione di thread interleaving per eseguire più thread rispetto alla CPU.
(Se lo farai, async è una forma leggera di parallelismo (pseudo), dove l'unica cosa è il thread principale, e l'altra cosa non è necessariamente un vero thread in piena regola, ma piuttosto una routine di completamento dell'I / O .)
Si noti inoltre che JavaScript è intrinsecamente a thread singolo. Vale a dire, non esiste una vera esecuzione parallela anche su un chip multiprocessore, mentre in C, C ++, Java o C #, si può avere davvero l'esecuzione simultanea di thread su un chip multiprocessore. JavaScript non ha nozioni di thread, ma ha callback.
Le callback (riferimenti alle funzioni) che fornite ad altre routine possono essere eseguite in modo sincrono o possono essere eseguite in modo asincrono. Dipende molto da come vengono utilizzati quei callback: in realtà non si può sapere dal codice che passa il callback (senza conoscere la routine della libreria a cui viene fornita la callback). Quindi i callback non implicano immediatamente l'esecuzione asincrona.
(I callback sono ulteriormente complicati in quanto il riferimento alla funzione può effettivamente essere usato zero o più volte, non c'è praticamente alcuna garanzia intrinseca dalla semantica del linguaggio su quando o quante volte viene usata una callback.)
Nel tuo esempio, sembrerebbe che i callback siano eseguiti in modo sincrono rispetto a - e sotto il controllo diretto di - il thread principale.
L'esecuzione asincrona avviene in JavaScript come risultato di routine di completamento I / O (o timeout). Poiché JavaScript è intrinsecamente a thread singolo, il modo in cui funziona è che il thread principale (uno) può essere eseguito al 100% di completamento - per tornare al suo chiamante (che è lo schedulatore JavaScript). A questo punto, non c'è più thread principale in esecuzione e, lo scheduler JavaScript può richiamare routine di completamento usando quel thread principale. Se più richieste di I / O attivano più routine di completamento, ciascuna viene eseguita al 100% al completamento, una dopo l'altra, nell'ordine in cui sono pianificate (che è l'ordine del completamento dell'I / O) senza interleaving.
(Naturalmente, la routine di completamento I / O può effettuare chiamate I / O aggiuntive, passando successivi callback di completamento I / O, l'esecuzione complessiva di tale serie di routine di completamento sarebbe intercalata con altri tali callback di completamento I / O come descritto sopra.)
Nel tuo caso, i callback vengono eseguiti dal richiamo di riferimento alla funzione, che li fa girare sotto il controllo regolare del thread principale. Il meccanismo è una chiamata di funzione indiretta, quindi i callback vengono richiamati utilizzando il meccanismo di chiamata della funzione standard. Il thread principale non viene eseguito fino al completamento; i callback non sono pianificati per essere eseguiti ma vengono richiamati piuttosto direttamente. Per vedere la differenza, potresti sostituire:
callback(null, result);
con
setTimeout(callback,100,null,result);
Ciò richiamerebbe anche il callback, ma attenderebbe qualche istante dopo la routine in esecuzione (e l'intero thread, di fatto) è tornato al suo chiamante.