J'ai plusieurs promesses que je dois tenir avant d'aller plus loin.
Promise.all(promises).then((results) => {
// going further
});
Existe-t-il un moyen de suivre la progression du Promise.all
promettre?
D'après le doc, il apparaît que ce n'est pas possible . Et cette question n'y répond pas non plus.
Alors:
J'ai créé une petite fonction d'aide que vous pouvez réutiliser.
En gros, passez vos promesses comme d'habitude et rappelez-vous pour faire ce que vous voulez avec la progression.
function allProgress(proms, progress_cb) {
let d = 0;
progress_cb(0);
for (const p of proms) {
p.then(()=> {
d ++;
progress_cb( (d * 100) / proms.length );
});
}
return Promise.all(proms);
}
function test(ms) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`Waited ${ms}`);
resolve();
}, ms);
});
}
allProgress([test(1000), test(3000), test(2000), test(3500)],
(p) => {
console.log(`% Done = ${p.toFixed(2)}`);
});
Vous pouvez ajouter un .then () à chaque promesse de compter les personnes terminées. quelque chose comme :
var count = 0;
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 5000, 'boo');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 7000, 'yoo');
});
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'foo');
});
var promiseArray = [
p1.then(function(val) {
progress(++count);
return val
}),
p2.then(function(val) {
progress(++count);
return val
}),
p3.then(function(val) {
progress(++count);
return val
})
]
function progress(count) {
console.log(count / promiseArray.length);
}
Promise.all(promiseArray).then(values => {
console.log(values);
});
Cela présente quelques avantages par rapport à réponse de Keith :
onprogress()
n'est jamais invoquée de manière synchrone. Cela garantit que le rappel peut dépendre du code qui est exécuté de manière synchrone après l'appel à Promise.progress(...)
.ProgressEvent
au lieu d'un pourcentage. Cela facilite la manipulation de 0 / 0
progresse les événements en évitant le quotient NaN
.Promise.progress = async function progress (iterable, onprogress) {
// consume iterable synchronously and convert to array of promises
const promises = Array.from(iterable).map(this.resolve, this);
let resolved = 0;
// helper function for emitting progress events
const progress = increment => this.resolve(
onprogress(
new ProgressEvent('progress', {
total: promises.length,
loaded: resolved += increment
})
)
);
// lift all progress events off the stack
await this.resolve();
// emit 0 progress event
await progress(0);
// emit a progress event each time a promise resolves
return this.all(
promises.map(
promise => promise.finally(
() => progress(1)
)
})
);
};
Notez que ProgressEvent
a un support limité . Si cette couverture ne répond pas à vos besoins, vous pouvez facilement remplir ceci:
class ProgressEvent extends Event {
constructor (type, { loaded = 0, total = 0, lengthComputable = (total > 0) } = {}) {
super(type);
this.lengthComputable = lengthComputable;
this.loaded = loaded;
this.total = total;
}
}
Voici mon point de vue à ce sujet. Vous créez un wrapper pour progressCallback et indiquez le nombre de threads dont vous disposez. Ensuite, pour chaque thread, vous créez un rappel distinct de ce wrapper avec l'index de thread. Threads chaque rapport via leur propre rappel comme auparavant, mais leurs valeurs de progression individuelles sont ensuite fusionnées et signalées via le rappel encapsulé.
function createMultiThreadProgressWrapper(threads, progressCallback) {
var threadProgress = Array(threads);
var sendTotalProgress = function() {
var total = 0;
for (var v of threadProgress) {
total = total + (v || 0);
}
progressCallback(total / threads);
};
return {
getCallback: function(thread) {
var cb = function(progress) {
threadProgress[thread] = progress;
sendTotalProgress();
};
return cb;
}
};
}
// --------------------------------------------------------
// Usage:
// --------------------------------------------------------
function createPromise(progressCallback) {
return new Promise(function(resolve, reject) {
// do whatever you need and report progress to progressCallback(float)
});
}
var wrapper = createMultiThreadProgressWrapper(3, mainCallback);
var promises = [
createPromise(wrapper.getCallback(0)),
createPromise(wrapper.getCallback(1)),
createPromise(wrapper.getCallback(2))
];
Promise.all(promises);
@Keith en plus de mon commentaire, voici une modification
(édité de façon détaillée, espérons-le)
// original allProgress
//function allProgress(proms, progress_cb) {
// let d = 0;
// progress_cb(0);
// proms.forEach((p) => {
// p.then(()=> {
// d ++;
// progress_cb( (d * 100) / proms.length );
// });
// });
// return Promise.all(proms);
//}
//modifying allProgress to delay 'p.then' resolution
//function allProgress(proms, progress_cb) {
// let d = 0;
// progress_cb(0);
// proms.forEach((p) => {
// p.then(()=> {
// setTimeout( //added line
// () => {
// d ++;
// progress_cb( (d * 100) / proms.length );
// }, //added coma :)
// 4000); //added line
// });
// });
// return Promise.all(proms
// ).then(()=>{console.log("Promise.all completed");});
// //added then to report Promise.all resolution
// }
//modified allProgress
// version 2 not to break any promise chain
function allProgress(proms, progress_cb) {
let d = 0;
progress_cb(0);
proms.forEach((p) => {
p.then((res)=> { //added 'res' for v2
return new Promise((resolve) => { //added line for v2
setTimeout( //added line
() => {
d ++;
progress_cb( (d * 100) / proms.length );
resolve(res); //added line for v2
}, //added coma :)
4000); //added line
}); //added line for v2
});
});
return Promise.all(proms
).then(()=>{console.log("Promise.all completed");});
//added then chaining to report Promise.all resolution
}
function test(ms) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`Waited ${ms}`);
resolve();
}, ms);
});
}
allProgress([test(1000), test(3000), test(2000), test(3500)],
(p) => {
console.log(`% Done = ${p.toFixed(2)}`);
});
"Promise.all done" sortira avant tout message de progression
voici la sortie que j'obtiens
% Done = 0.00
Waited 1000
Waited 2000
Waited 3000
Waited 3500
Promise.all completed
% Done = 25.00
% Done = 50.00
% Done = 75.00
% Done = 100.00