urls = [url1, url2, url3]
Déclenchez les 3 URL en parallèle et peignez le Dom dans l'ordre de la liste des URL p >
from(urls) .pipe( mergeMap(x => fetch(x)) )
Mon travail avec des promesses:
// Fired all 3 urls at the same time p1 = fetch(url1) p2 = fetch(url2) p3 = fetch(url3) p1.then(updateDom) .then(() => p2) .then(updateDom) .then(() => p3) .then(updateDom)
Je voulais faire la même chose dans Observables.
ex: Finished order of urls = [url3, url1, url2] when url1 finishes Immediately render the DOM, without waiting for url2 If url2, url3 finishes before url1, then store url2, url3 and paint the DOM after url1 arrives Paint the DOM with order [url1, url2, url3]
Pour les lancer en parallèle, j'ai utilisé une carte de fusion, mais comment puis-je ordonner la séquence des résultats?
3 Réponses :
Vous pouvez former une séquence avec fetch and paint puis forkJoin / Promise.all them
p1 = fetch(url1) p2 = fetch(url2) p3 = fetch(url3) forkJoin( from(p1).pipe(tap(_=>paint dom...)) from(p1).pipe(tap(_=>paint dom...)) from(p1).pipe(tap(_=>paint dom...)) ).subscribe()
Je n'ai rien trouvé qui préserve l'ordre, alors j'ai trouvé quelque chose d'un peu compliqué.
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>
const { concat, of, BehaviorSubject, Subject } = rxjs; const { delay, filter } = rxjs.operators; const parallelExecute = (...obs$) => { const subjects = obs$.map(o$ => { const subject$ = new BehaviorSubject(); const sub = o$.subscribe(o => { subject$.next(o); }); return { sub: sub, obs$: subject$.pipe(filter(val => val)) }; }); const subject$ = new Subject(); sub(0); function sub(index) { const current = subjects[index]; current.obs$.subscribe(c => { subject$.next(c); current.obs$.complete(); current.sub.unsubscribe(); if (index < subjects.length -1) { sub(index + 1); } else { subject$.complete(); } }); } return subject$; } parallelExecute( of(1).pipe(delay(3000)), of(2).pipe(delay(2000)), of(3).pipe(delay(1000)) ).subscribe(result => { console.log(result); });
La meilleure façon de préserver l'ordre avec des tâches asynchrones comme celle-ci est d'utiliser concatMap a >. Le problème est que si nous appliquons cela seul, nous perdons la parallélisation. Si nous devions faire quelque chose comme ceci: la deuxième requête n'est pas lancée tant que la première n'est pas terminée. Nous pouvons contourner cela en séparant la carte en son propre opérateur: La requête sera lancée en même temps les résultats seront émis dans l'ordre de la demande. Voir l'exemple d'Adrian adapté pour utiliser cette approche ci-dessous: <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>
const { from } = rxjs;
const { concatMap, map } = rxjs.operators;
function delayPromise(val, delay) {
return new Promise(res => setTimeout(() => res(val), delay));
}
var delay = 3;
from([1, 2, 3]).pipe(
map(x => delayPromise(x, delay-- * 1000)),
concatMap(x => x)
).subscribe(result => { console.log(result); });
from(urls)
.pipe(
map(x => fetch(x)),
concatMap(x => x)
)
from(urls)
.pipe(
concatMap(x => fetch(x))
)
Merci pour la solution. Mais désolé, je ne peux accepter qu'une seule réponse.
@pawankumar c'est tout bon, je le postais juste au cas où d'autres personnes trouveraient cette question
Désolé, je ne voulais pas dire cela, j'ai trouvé votre réponse bien meilleure que celle acceptée. Je voulais dire cela d'une manière amusante.
Oui, cela devrait être la réponse acceptée. Bon travail.
Je viens de regarder cette vidéo et cela m'a rappelé cette question youtu.be/ZdS9uOl4OJk?t=2025 voici le code codesandbox.io/s/dreamy- bas-nmw6x? file = / src / ordersMergeMap. ts