2015-12-09 16 views
5

Come faccio a fare qualcosa come $q.all ma limitando quante promesse vengono eseguite contemporaneamente?

La mia domanda è come How can I limit Q promise concurrency?

voglio non più di 5 processo ha generato in un momento

La risposta accettata per quella altra domanda è una libreria scritta per promise avvolto con cui lavorare Q. Ma sono interessato in particolare a una soluzione per Angular $q anziché per Q.

Contesto: Il problema viene risolto:
Ho un sacco di file da scaricare in 2 fasi: a) Get URL b) scaricare il file.
Il browser limita il numero di file che possono essere recuperati contemporaneamente, quindi quando l'uso diretto delle promesse con $q.all spegne tutti i download, solo
N avviene immediatamente, ad es. in Chrome, mentre il resto è in ritardo. (vedi Max parallel http connections in a browser?)
problema è che gli URL hanno scadenza, quindi per il momento il browser esegue il N + 1 ° download di file, l'URL non è più valida.
Quindi voglio fare qualcosa di simile throttled.all(6, promises) piuttosto che $q.all(promise)

risposta

0

Penso che si potrebbe fare qualcosa ricorsiva.

Ciò consentirebbe di utilizzare solo $q. Si potrebbe solo avere una lista si sarebbe utilizzando, che è necessario comunque per $q.all

self.MakeCall = function(theList, chunkSize){ 
    //Split list into what will be processed and what should be held 
    var processList = theList.slice(0,chunkSize); 
    var holdList = theList.slice(chunkSize); 

    return $q.all(processList).then(function(result) { 
     //If holdList is empty you are finished 
     if(holdList <= 0) { 
     return result; 
     } 
     else { 
     //More items make recursive call to process next set 
     return self.MakeCall(holdList, chunkSize); 
     } 
    }); 
    }; 
//Initialize Recursive call 
self.MakeCall(self.contacts); 
+1

Non male, @Malkus, grazie. Non è così concorrente come immaginavo, dal momento che il tuo esempio si rompe in blocchi di dimensione N, piuttosto che avere sempre promesse N in esecuzione ... detto questo, è sicuramente molto più concorrente di una catena sequenziale! :) – Daryn

0

Ecco una soluzione alternativa che verrà eseguito Bocconcini simultanei. Non è così pulito come l'altra risposta, ma è più vicino a quello che stai cercando.

Ho lasciato alcuni markup utilizzati per la convalida.

self.list [...]; 

self.MakeCall = function(theList, chunkSize,methodTracker){ 
    //Set default chunkSize 
    chunkSize = (chunkSize)?chunkSize:1; 

    //Slice list using previously defined list 
    // so multiple instances can be runuse same list 
    var processList = self.list.slice(0,chunkSize); 
    self.list = self.list.slice(chunkSize); 

    return $q.all(processList).then(function(result) { 
     //If holdList is empty you are finished 
     if(self.list <= 0) { 
     console.debug("method last: " + methodTracker); 
     return result; 
     } 
     else { 
     //More items make recursive call to process next set 
     console.debug("method: " + methodTracker); 
     return self.MakeCall(self.list, chunkSize,methodTracker); 
     } 
    }); 
    }; 
    //Initialize Recursive call 
    self.MakeCall(self.list,1,1).then(function() { 
    console.warn('end 1'); 
    }); 
    //Initialize Second call that will run asynchronous with the first 
    // this can be initialized as many times as you want concurrent threads 
    self.MakeCall(self.list,1,2).then(function() { 
    console.warn('end 2'); 
    }); 

ho optato per mettere in un'altra risposta. Credo che i due sono abbastanza differenti che non ho voglia di apportare modifiche per l'altra

0

ho provato un paio di metodi diversi per fare questo, ma alla fine si stabilirono a scrivere un'estensione $q che si estende il suo comportamento con $q.all$q.allLimit().

Vedere il modulo angular-q-limit per ulteriori dettagli.

Il modulo funziona creando una funzione di avvolgimento che prende una serie di Promises e li esegue nella sequenza ordinata (limitando l'esecuzione simultanea al limite) finché tutti non sono esauriti. Quindi risolve la propria promessa con i valori di ritorno di tutti allo stesso modo di $q.all().

+0

Si prega di vedere come funziona invece di incollare semplicemente un collegamento alla libreria. – Bergi

+1

Questo non ha senso. [È impossibile] (http://stackoverflow.com/q/30823653/1048572) per sequenziare 'all'. – Bergi

+0

Scuse. Ho aggiunto alcuni esempi qui: https://gist.github.com/hash-bang/652be06e3cf89f9d71fa2dfceb893719 - Se puoi essere più specifico su ciò che stai cercando di richiedere, posso scrivere qualcosa. –

0

Se la risoluzione di "tutte le promesse" è irrilevante (come se si aggiorni alcuni elementi nella pagina e non ti interessa se è progressivo e non in un "whoosh") ho creato un semplice servizio TaskQueue. Non aspetterà che tutte le promesse siano risolte, ma piuttosto elaborerà tutte le promesse/funzioni/attività aggiunte che ottiene e con un max. concomitanza di un valore limite configurato.

Come ho trovato solo questo e alcuni altri StackOverflow che non aiutano il mio problema. Quindi ora restituisco qualcosa alla comunità, credo. Spero che aiuti qualcuno.

Usa roba JS moderna come le espressioni const e lambda, ma puoi semplicemente lasciarlo compilare da un precompilatore come babel se vuoi solo le cose "vecchie".

https://gist.github.com/Blackskyliner/8b1bafed326044fa4f8b1ba2627d1117

elabora semplicemente la sua coda dopo le attività, che sono solo funzioni anonime, restituendo una promessa o un valore, vengono aggiunti. Aderisce a una variabile configurabile 'maxConcurrentTasks' sul servizio.

Se l'attività restituisce una promessa che restituisce una promessa e così via utilizzerà sempre lo "slot" iniziale all'interno della coda. Quindi libererà lo 'slot' per un'altra attività aggiunta dopo che l'intera catena di Promessa attività è stata risolta (o rifiutata).