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);
})();