ForEach di fetch asincroni e paralleli

di il
4 risposte

ForEach di fetch asincroni e paralleli

Ciao a tutti
Un po' di confusione sulle chiamate asincrone e parallele...
Illuso che con XMLHttpRequest io stessi inviando asincrone e parallele e invece mi sa che non sto facendo niente, perché forse è meglio usare async/await e Promise... vero?

Vorrei chiamare una funzione asincronicamente (non deve aspettare risposta)
Questa funzione ha un array di 50 elementi, io vorrei che si inviassero 50 get asincroni e in parallelo, o comunque decidere io quanti inviarne in parallelo
	
var x = send_();
function send_(){
	const invia = new XMLHttpRequest();
	completate.forEach(b => {
			invia5.open("GET",url, true);
			invia5.send(null);
	});
}
Correggetemi se sbaglio, da quel poco che ho capito io...
Tutto questo di asincrono e parallelo ha quasi niente, perché var x aspetta una risposta da send_(); e quindi lo script non prosegue.
XMLHttpRequest invia 50 get asincroni (true) ma non paralleli, perché li invia uno dopo l'altro senza aspettare risposta... e forse nemmeno di asincrono ha molto perché c sono i limiti di connessioni simultanee impostate dal browser e dal server, giusto? Che ho letto su internet essere 6... quindi oltre che esserci nulla di parallelo è anche tutto asincrono per modo di dire... perché dopo averne inviato 6, aspetta che 1 abbia ricevuto risposta per inviare il 7, è così?

devo quindi chiamare send_() in modo asincrono perché non mi interessa che aspetti la risposta.
devo poi lanciare 50 get asincroni e in parallelo, tra l'altro non mi interessa nemmeno processare risposte, perché i 50get fanno degli INSERT nel db. Da un'altra parte c'è un setInterval (che non è davvero asincrono ho scoperto!... ) che controlla il db ogni tot secondi, quindi non mi interessa processare risposte.

Conviene creare un array di fetch e passarli a Promise.allSettled? Tipo
var arr = [ fetch('url'), fetch('url'), fetch('url'), fetch('url') ]
async function send_(){
Promise.allSettled(arr);
}
in questo caso è tutto diventerebbe tutto asincrono e parallelo senza processare risposta?

Scusate il macello, ci sono ore leggendo e oltre che essere stanco sono pure confuso, non ho ancora dormito

Grazie per l'aiuto

4 Risposte

  • Re: ForEach di fetch asincroni e paralleli

    melixo ha scritto:


    XMLHttpRequest invia 50 get asincroni (true) ma non paralleli, perché li invia uno dopo l'altro senza aspettare risposta...
    Non mi è chiaro cosa intendi per "paralleli": qualsiasi operazione venga eseguita ne precede una e ne segue un'altra, indicativamente.

    Se l'operazione tratta banalmente l'avvio di qualcosa di asincrono, e che quindi richiede tempo ma ritorna subito fornendo un callback o uno strumento per identificare il termine delle operazioni, si può dire che le operazioni avvengano in parallelo perché un eventuale ciclo le fa partire virtualmente tutte assieme.

    melixo ha scritto:


    e forse nemmeno di asincrono ha molto perché c sono i limiti di connessioni simultanee impostate dal browser e dal server, giusto? Che ho letto su internet essere 6... quindi oltre che esserci nulla di parallelo è anche tutto asincrono per modo di dire... perché dopo averne inviato 6, aspetta che 1 abbia ricevuto risposta per inviare il 7, è così?
    Qui ti scontri con le limitazioni impostate sul server che potrebbero essere personalizzate e accettare un numero di chiamate contemporanee variabile.

    melixo ha scritto:


    devo poi lanciare 50 get asincroni e in parallelo, tra l'altro non mi interessa nemmeno processare risposte, perché i 50get fanno degli INSERT nel db. Da un'altra parte c'è un setInterval (che non è davvero asincrono ho scoperto!... ) che controlla il db ogni tot secondi, quindi non mi interessa processare risposte.
    Innanzitutto, perché non inviare le 50 informazioni tutte con un'unica chiamata? Trovo la scelta delle chiamate separate abbastanza inefficiente.

    Inoltre, non dovresti creare un nuovo oggetto XMLHttpRequest per ogni richiesta? Usare sempre lo stesso oggetto potrebbe cambiarne la destinazione d'uso nel ciclo prima che l'operazione precedentemente avviata sia terminata in qualche modo.

    E ancora, non legherei una operazione di inserimento (che quindi altera il sistema remoto) a un comando GET, ma userei piuttosto un POST.

    Cosa intendi con "setInterval() non è davvero asincrono"? Non mi risulta, tant'è che passi un callback per indicare la funzione da eseguire.

    melixo ha scritto:


    Conviene creare un array di fetch e passarli a Promise.allSettled?
    in questo caso è tutto diventerebbe tutto asincrono e parallelo senza processare risposta?
    Sicuramente, in termini di leggibilità e modernità del codice, sarebbe una soluzione migliore.
    Il metodo Promise.allSettled() ti restituisce appunto una promise a cui puoi agganciare un callback (con il metodo then()) da eseguire quando tutte le promise specificate come parametro sono state concluse (indipendentemente dall'esito).

    Le operazioni avvengono in modo asincrono, così come il loro controllo.
    "Parallelo" non so, non ha senso come termine: se lanci due operazioni che stanno eseguendo in background nello stesso momento, sono parallele, no? Ma questo vale per tutti i contesti analoghi a questo.

    Ciao!
  • Re: ForEach di fetch asincroni e paralleli

    Alka ha scritto:


    melixo ha scritto:


    XMLHttpRequest invia 50 get asincroni (true) ma non paralleli, perché li invia uno dopo l'altro senza aspettare risposta...
    Non mi è chiaro cosa intendi per "paralleli": qualsiasi operazione venga eseguita ne precede una e ne segue un'altra, indicativamente.
    Perché facendo ricerche ho letto che funzioni async possono essere inviate in sequenza o in parallelo, ma in realtà la cosa sarebbe talmente veloce che in sequenza o in parallelo è praticamente uguale

    Se l'operazione tratta banalmente l'avvio di qualcosa di asincrono, e che quindi richiede tempo ma ritorna subito fornendo un callback o uno strumento per identificare il termine delle operazioni, si può dire che le operazioni avvengano in parallelo perché un eventuale ciclo le fa partire virtualmente tutte assieme.

    melixo ha scritto:


    e forse nemmeno di asincrono ha molto perché c sono i limiti di connessioni simultanee impostate dal browser e dal server, giusto? Che ho letto su internet essere 6... quindi oltre che esserci nulla di parallelo è anche tutto asincrono per modo di dire... perché dopo averne inviato 6, aspetta che 1 abbia ricevuto risposta per inviare il 7, è così?
    Qui ti scontri con le limitazioni impostate sul server che potrebbero essere personalizzate e accettare un numero di chiamate contemporanee variabile.
    dovrei controllare sul server a quanto è impostato... poi vedrò come si trova questo valore... spero non siano una manciata...

    melixo ha scritto:


    devo poi lanciare 50 get asincroni e in parallelo, tra l'altro non mi interessa nemmeno processare risposte, perché i 50get fanno degli INSERT nel db. Da un'altra parte c'è un setInterval (che non è davvero asincrono ho scoperto!... ) che controlla il db ogni tot secondi, quindi non mi interessa processare risposte.
    Innanzitutto, perché non inviare le 50 informazioni tutte con un'unica chiamata? Trovo la scelta delle chiamate separate abbastanza inefficiente.
    Sì, in realtà sarebbe meglio inviare 50 valori in un solo lancio ad una pagina php
    Il problema è che non me li processerebbe tutti insieme, ma uno dopo l'altro.
    Mentre io pensavo di inviare 50 get separati così vengono processati più o meno tutti insieme... e avrei 50 risultati, credo, più velocemente.
    Sarebbe da valutare se 50 pagine gestiscano più velocemente un valore ciascuna, oppure una pagina 50 valori.
    Inoltre, non dovresti creare un nuovo oggetto XMLHttpRequest per ogni richiesta? Usare sempre lo stesso oggetto potrebbe cambiarne la destinazione d'uso nel ciclo prima che l'operazione precedentemente avviata sia terminata in qualche modo.
    Sì, ho sbagliato... ma quindi il successivo XMLHttpRequest non parte se il precedente non ha finito? Anche se impostato true per asincrono?? Se è così mi sparo...
    E ancora, non legherei una operazione di inserimento (che quindi altera il sistema remoto) a un comando GET, ma userei piuttosto un POST.
    intendi per una questione di sicurezza, in quanto il codice javascript è visibile a tutti?
    Cosa intendi con "setInterval() non è davvero asincrono"? Non mi risulta, tant'è che passi un callback per indicare la funzione da eseguire.
    perché ho letto che impostando un setInterval a 1000 non è detto che venga eseguito ogni secondo, perché se l'operazione impiega più di quel tanto allora setInterval aspetta...

    melixo ha scritto:


    Conviene creare un array di fetch e passarli a Promise.allSettled?
    in questo caso è tutto diventerebbe tutto asincrono e parallelo senza processare risposta?
    Sicuramente, in termini di leggibilità e modernità del codice, sarebbe una soluzione migliore.
    Il metodo Promise.allSettled() ti restituisce appunto una promise a cui puoi agganciare un callback (con il metodo then()) da eseguire quando tutte le promise specificate come parametro sono state concluse (indipendentemente dall'esito).
    Leggendo sulle Promise ho letto che in base alla risposta potrebbe bloccarsi, ma a me non interessano le risposte e volevo che si concludesse tutto, e ho letto che Promise.allSettled ovvia a questo.

    Le operazioni avvengono in modo asincrono, così come il loro controllo.
    "Parallelo" non so, non ha senso come termine: se lanci due operazioni che stanno eseguendo in background nello stesso momento, sono parallele, no? Ma questo vale per tutti i contesti analoghi a questo.

    Ciao!
  • Re: ForEach di fetch asincroni e paralleli

    melixo ha scritto:


    Perché facendo ricerche ho letto che funzioni async possono essere inviate in sequenza o in parallelo, ma in realtà la cosa sarebbe talmente veloce che in sequenza o in parallelo è praticamente uguale
    Occhio che l'uso di async (mi premuro di verificare quanto dico) non è altro che "zucchero sintattico", ovvero una parola chiave che consente di scrivere codice in un certo modo, ma alla fine rispetto all'uso di Promise non cambia nulla nella sostanza.

    melixo ha scritto:


    dovrei controllare sul server a quanto è impostato... poi vedrò come si trova questo valore... spero non siano una manciata...
    Io spero di sì: se nel caricamento di un pacchetto di informazioni il server dovesse gestire il loro invio separato per un numero magari elevato di utenti, il sistema crollerebbe facilmente se non è costruito in modo da essere scalabile.

    melixo ha scritto:


    Sì, in realtà sarebbe meglio inviare 50 valori in un solo lancio ad una pagina php
    Il problema è che non me li processerebbe tutti insieme, ma uno dopo l'altro.
    Ma questo avviene comunque: il collo di bottiglia in questo caso è costituito dal DB, che suppongo accetti una sola INSERT alla volta (virtualmente le accetta tutte, ma poi fisicamente le prenderà in carico in modo sequenziale).

    melixo ha scritto:


    Mentre io pensavo di inviare 50 get separati così vengono processati più o meno tutti insieme... e avrei 50 risultati, credo, più velocemente. Sarebbe da valutare se 50 pagine gestiscano più velocemente un valore ciascuna, oppure una pagina 50 valori.
    Secondo me, non c'è neanche da misurarlo: la chiamata HTTP ha un suo peso (guarda le dimensioni del pacchetto dati che vai ad inviare e quello in ricezione), quindi ha un suo tempo non indifferente per il trasferimento e la relativa esecuzione; ogni singola chiamata prende in carico solo una porzione piccola di dati, quindi il server deve eseguire la pagina PHP (spendendo altro tempo) per elaborare una minuscola frazione del pacchetto complessivo. Tutto questo per evitare di "serializzare" una operazione di inserimento su un DB che, fra tutte quelle elencate, è quella più veloce.

    In poche parole, per evitare di sequenziare una operazione molto veloce che verrebbe comunque serializzata, stai "splittando" 50 dati in unità singole, ripetendo chiamate HTTP (richiesta e risposta), la loro serializzazione ed elaborazione per ciascuna porzione di dati, quando potresti unire tutte queste operazioni dispendiose in una operazione unica.

    E' un po' come dire che, dovendo mettere in frigorifero un prodotto alla volta dalla spesa al supermercato, ottimizzi andando a fare la spesa una volta per ogni singolo prodotto (quindi prendendo il carrello, prelevando il prodotto, passandolo alla cassa, portandolo a casa, ecc.).

    E se domani i dati da 50 diventano 100, 500, 1000?

    Puoi dire addio alla tua soluzione, nonostante si tratti di numeri ancora bassi.
    Sì, ho sbagliato... ma quindi il successivo XMLHttpRequest non parte se il precedente non ha finito? Anche se impostato true per asincrono?? Se è così mi sparo...
    Se crei diversi oggetti, non credo ci siano problemi, ma forse qui semplificheresti (come ti è stato suggerito altrove) usando direttamente fetch(), che è più semplice e ha un approccio più moderno.
    intendi per una questione di sicurezza, in quanto il codice javascript è visibile a tutti?
    No, fare una GET o una POST cambia un parametro nel codice, che rimane altrettanto visibile: la differenza sta nel fatto che le operazioni di GET si riferiscono generalmente a indirizzi con parametri che si possono specificare anche nella barra degli indirizzi del browser, e non è corretto che a questo tipo di accesso - che potrebbe avvenire anche involontariamente, dato che il browser memorizza gli URL nella cronologia e li ripropone - corrisponda una operazione virtualmente "distruttiva" o comunque che altera lo stato del sistema esposto via API (nel nostro caso, facendo le INSERT su DB).

    Nello sviluppo di API REST, l'ideale sarebbe rispettare i dettami descritti nel Richardson Maturity Model (che contiene un esempio interessante di colloquio con il server, passando da un uso "volgare" dell'HTTP a una API correttamente strutturata).
    perché ho letto che impostando un setInterval a 1000 non è detto che venga eseguito ogni secondo, perché se l'operazione impiega più di quel tanto allora setInterval aspetta...
    Quello che dici non esclude che si tratti comunque di una operazione asincrona.

    Il comportamento descritto deriva dal funzionamento a singolo thread della gestione degli eventi di JavaScript: ogni operazione asincrona avviene in background su un thread separato che al termine dell'operazione inserisce il callback nel loop degli eventi per segnalare la fine della suddetta operazione. Questo vuol dire che ciascun setInterval() impostato a 1000 inserirà nel loop degli eventi un callback "precisamente" ogni secondo, però se il codice JavaScript che sta gestendo un altro callback si dilunga nell'esecuzione, gli eventi di callback inseriti con precisione rimarranno in coda in attesa di essere gestiti, fino a quando il callback corrente e quelli successivi non verranno eseguiti. E' il motivo per cui ogni operazione lunga va evitata nelle funzioni ma delegata a un processo in background (asincrono) che segnali tramite callback la propria fine, e che la gestione del callback sia la più rapida possibile.

    melixo ha scritto:


    Leggendo sulle Promise ho letto che in base alla risposta potrebbe bloccarsi, ma a me non interessano le risposte e volevo che si concludesse tutto, e ho letto che Promise.allSettled ovvia a questo.
    Il metodo allSettled() ti restituisce una Promise che viene "risolta" quando tutte le Promise specificate come parametro sono terminate (sono in stato "settled"), indipendentemente dal fatto che siano andate a buon fine o in errore.

    P.S.: quota meglio i messaggi nelle risposte, perché nell'ultimo intervento non si capiva nulla di qual era la mia parte e la tua risposta.

    Ciao!
  • Re: ForEach di fetch asincroni e paralleli

    Grazie Alka per la miriade di informazioni e per la disponibilità, sto incominciando a capirci un po' di più. Il problema è che ho anche libri vecchi, rimasti ancora a XMLHttpRequest. Magari proprio inutili non saranno però per fortuna c'è anche internet converrà comprarmi roba più recente.
    Grazie mille, sei molto gentile
Devi accedere o registrarti per scrivere nel forum
4 risposte