Javascript 承诺一切进步
我有几个承诺,我需要解决,然后再进一步Javascript 承诺一切进步,javascript,es6-promise,Javascript,Es6 Promise,我有几个承诺,我需要解决,然后再进一步 Promise.all(promises).then((results) => { // going further }); 有没有办法让我了解一下承诺的进展情况。所有的承诺 从文档中可以看出。也没有回答 因此: 你不认为这会有用吗?我们不应该查询此功能吗 现在如何手动实现它 您可以在每个承诺中添加一个.then(),以计算谁完成了。 比如: var计数=0; 风险值p1=新承诺((解决、拒绝)=>{ setTimeout(解析,5000
Promise.all(promises).then((results) => {
// going further
});
有没有办法让我了解一下承诺的进展情况。所有的承诺
从文档中可以看出。也没有回答
因此:
- 你不认为这会有用吗?我们不应该查询此功能吗
- 现在如何手动实现它
您可以在每个承诺中添加一个.then(),以计算谁完成了。
比如:
var计数=0;
风险值p1=新承诺((解决、拒绝)=>{
setTimeout(解析,5000,'boo');
});
var p2=新承诺((解决、拒绝)=>{
setTimeout(解析,7000,'yoo');
});
var p3=新承诺((解决、拒绝)=>{
setTimeout(解析,3000,'foo');
});
变量promiseArray=[
p1.然后(功能(val){
进度(++计数);
返回值
}),
p2.然后(函数(val){
进度(++计数);
返回值
}),
p3.然后(功能(val){
进度(++计数);
返回值
})
]
功能进度(计数){
log(count/promiseArray.length);
}
promiseArray.then(值=>{
console.log(值);
});代码>我设计了一个小助手函数,您可以重复使用
基本上,像平常一样兑现你的承诺,并提供一个回调来实现你想要的进展
function allProgress(proms,progress\u cb){
设d=0;
进展情况(0);
for(舞会常数){
p、 然后(()=>{
d++;
进度(d*100)/proms.length;
});
}
返回承诺。全部(proms);
}
功能测试(ms){
返回新承诺((解决)=>{
设置超时(()=>{
log(`Waited${ms}`);
解决();
},ms);
});
}
所有进度([测试(1000)、测试(3000)、测试(2000)、测试(3500)],
(p) =>{
log(`%Done=${p.toFixed(2)}`);
});代码>@Keith除了我的评论之外,这里还有一个修改
(编辑以完全详细说明希望)
“Promise.all completed”将在任何进度消息之前输出
这是我得到的输出
% 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
这是我的看法。您为progressCallback创建一个包装器,并告知您有多少线程。然后,对于每个线程,使用线程索引从这个包装器创建一个单独的回调。线程和以前一样,每个线程都通过自己的回调进行报告,但随后它们各自的进度值被合并并通过包装的回调进行报告
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);
相比之下,这有几个优点:
onprogress()
回调永远不会同步调用。这确保了回调可以依赖于调用Promise.progress(…)
后同步运行的代码
- 承诺链将进程中抛出的错误传播给调用方,而不允许未捕获的承诺拒绝。这确保了通过健壮的错误处理,调用方能够防止应用程序进入未知状态或崩溃
- 回调收到的是一个百分比,而不是一个百分比。通过避免商
NaN
,这降低了处理0/0
进度事件的难度
请注意。如果此保险范围不符合您的要求,您可以轻松填写:
class ProgressEvent extends Event {
constructor (type, { loaded = 0, total = 0, lengthComputable = (total > 0) } = {}) {
super(type);
this.lengthComputable = lengthComputable;
this.loaded = loaded;
this.total = total;
}
}
您可以与支持高级进度捕获(包括嵌套承诺)的本机承诺的扩展版本一起使用
或具有并发限制():
您可以始终拥有promises
数组的长度,并使用incrementCount()
之类的函数从每个promise回调递增一个共享变量值,然后在同一对象上创建getPercent()之类的函数
返回counter*100/promises.length
,每次解析或拒绝都发生在每个promise上。您可以通过向每个promise添加。然后()
来模拟promise.progress(),然后再将它们推送到数组中,您将promise.all()
。这会有一点额外的开销,但也很方便。非常好的解决方案。我的2美分:第10行可能不是“Promise.all(proms)”,因为您可能希望第5行中构建的“p.then()”在声明该承诺之前得到解析。所有操作都完成了。如果这些“then”确实调用了一些异步,比如dom更新之类的(在这种情况下,您可能需要为其返回一些新的承诺)…@user3617487谢谢<代码>p。那么
是一个承诺,它在完成之前不应该解决,它不应该关心它是否调用了一些异步
代码,如果它调用了,那么这将需要成为承诺的一部分。IOW:p.那么
不应该完成,直到它完成...)把p上的要点放在一边,然后返回承诺或不返回。只要记住“Promise.all(proms);”不会等待proges的更新。但同样,如果这些更新是同步的,这是一个细节。@user3617487不确定您的目的是什么,Promise。所有的只有在所有的承诺都已解决时才会解决,这就是Promise.all
所做的。你可能会找到一个片段来说明你的意思,在这里添加一个答案,因为它仍然是开放的<代码>如果这些更新是同步的
更新永远不应该是同步的,“[返回承诺.all(proms);”等待来自“allProgress”([测试(1000)、测试(3000)、测试(2000)、测试(3500)],…”的承诺,这些将在“然后(()=>{d++;…”之前完成”是执行的。我担心我无法在注释中键入代码。我将在另一个答案中添加一个snipet。我想你可能会对此感到困惑,为什么要在然后回调中添加setTimeout
。。你基本上打破了承诺链。是这样吗?据我所知,setTimeout只是模拟异步计算的常用工具(这里举例说明dom中的一些更新)。事实上,我没有得到你所说的“承诺链”。如果你能启发我:)?setTimeout
非常适合模拟async
操作,但它本身并不是一个promise
,这就是
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)
)
})
);
};
class ProgressEvent extends Event {
constructor (type, { loaded = 0, total = 0, lengthComputable = (total > 0) } = {}) {
super(type);
this.lengthComputable = lengthComputable;
this.loaded = loaded;
this.total = total;
}
}
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]
})();
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);
})();