在进一步讨论之前,我需要解决几项承诺。
Promise.all(promises).then((results) => {
// going further
});
我有什么方法可以取得Promise.all
承诺的进展吗?
从文档中可以看出it is not possible。并且this question也没有回答。
所以:
答案 0 :(得分:24)
我已经敲了一个你可以重复使用的辅助功能。
基本上按照惯例传递你的承诺,并提供一个回调来做你想要的进展..
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)}`);
});

答案 1 :(得分:4)
您可以为每个承诺添加.then()以计算完成的数量。 类似的东西:
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);
});

答案 2 :(得分:1)
与Keith's answer相比,它有一些优点:
Promise.all()
接受,而不仅仅是数组ProgressEvent
而不是百分比,因此您可以访问已解决的整数的promise和总金额Promise.progress = async function progress (iterable, onprogress) {
await this.resolve()
const promises = Array
.from(iterable)
.map(this.resolve, this)
const { length } = promises
let resolved = 0
const values = promises.map(async promise => {
const value = await promise
const event = new ProgressEvent('progress', {
total: length,
loaded: ++resolved
})
await this.resolve(onprogress(event))
return value
})
const event = new ProgressEvent('progress', {
total: length,
loaded: resolved
})
await this.resolve(onprogress(event))
return this.all(values)
}
ProgressEvent
has limited support显然不明显。如果这困扰您,您可以轻松添加:
class ProgressEvent extends Event {
constructor (type, { loaded = 0, total = 0 } = {}) {
super(type)
this.loaded = loaded
this.total = total
}
}
答案 3 :(得分:0)
@Keith除了我的评论外,这是一个修改
(编辑以详细说明希望)
// 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)}`);
});
“承诺全部完成”将在任何进度消息之前输出
这是我得到的输出
% 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
答案 4 :(得分:0)
这是我的看法。您为progressCallback创建一个包装器,并告诉您有多少个线程。然后,对于每个线程,使用线程索引从该包装创建一个单独的回调。像以前一样,每个线程都通过自己的回调来报告,但是随后,它们各自的进度值将通过合并的回调进行合并和报告。
{,,foobar64d.dll}global::foo
答案 5 :(得分:0)
您可以将 my npm package 与原生承诺的扩展版本一起使用,该版本支持开箱即用的高级进度捕获,包括嵌套承诺Live sandbox
import { CPromise } from "c-promise2";
(async () => {
const results = await CPromise.all([
CPromise.delay(1000, 1),
CPromise.delay(2000, 2),
CPromise.delay(3000, 3),
CPromise.delay(10000, 4)
]).progress((p) => {
console.warn(`Progress: ${(p * 100).toFixed(1)}%`);
});
console.log(results); // [1, 2, 3, 4]
})();
或者有并发限制(Live sandbox):
import { CPromise } from "c-promise2";
(async () => {
const results = await CPromise.all(
[
"filename1.txt",
"filename2.txt",
"filename3.txt",
"filename4.txt",
"filename5.txt",
"filename6.txt",
"filename7.txt"
],
{
async mapper(filename) {
console.log(`load and push file [${filename}]`);
// your async code here to upload a single file
return CPromise.delay(1000, `operation result for [${filename}]`);
},
concurrency: 2
}
).progress((p) => {
console.warn(`Uploading: ${(p * 100).toFixed(1)}%`);
});
console.log(results);
})();