【问题标题】:How to run "x" promises in parallel Javascript如何在并行 Javascript 中运行“x”承诺
【发布时间】:2018-08-26 11:58:05
【问题描述】:

我有一个函数“promiseFunction”,它返回一个承诺,它会在以后解决。

我需要多次调用此函数,但我只希望一次执行该函数的设定次数。

该函数在我的计算机上调用一些外部单线程 c 代码,如果我一次调用太多此代码的实例,我的系统会崩溃,但如果我一次按顺序调用它 1,它会非常慢,因为只有一个线程我的 cpu 正在做任何工作。

所以我想出了下面的代码,但是它不起作用。它将并行调用前 10 个 Promise,但慢慢地它开始一次调用越来越少的 Promise,直到它一次只调用 1 个 Promise。

var totalNumberOfPromises = // total number times to run promiseFunction;
var promiseCounter = 0; // keep track of which promise call this is 
for(w=0;w<10;w++){ // run 10 promises at a time
  promiseFunction().then(function(resolve) {
    loadNewPromise();
  })
  promiseCounter++;
}

function loadNewPromise(){

  if(promiseCounter<totalNumberOfPromises){
    promiseFunction().then(function(resolve) {  loadNewPromise(); });
  }else{
    alert("Finished");
  }
  promiseCounter++;
}

上面的代码有什么问题会导致这种行为吗?有没有这样做的标准方法?

【问题讨论】:

  • 我至少看到一件事:在代码的第二部分,promiseFunction.then 没有调用 promiseFunction
  • 它正在调用 loadNewPromise(),它是调用 promiseFunction() 的父函数。这将如何导致问题?
  • 在顶部代码中,您有promiseFunction().then,但在底部,您有promiseFunction.then.then 应该只在 promises 上调用,而不是函数
  • which returns a promise when the function is complete - 实际上,它返回一个承诺,该承诺会在稍后解决 - 但技术细节可能会令人困惑
  • @CertainPerformance 哦,我看到了错误,抱歉,这是转换为伪代码的错误。使用我的真实代码,我都成功调用了

标签: javascript callback promise


【解决方案1】:

这是我之前准备的一个函数(我已经用了几年了,就是为了这样的事情

const multiQueue = length => {
    length = (isNaN(length) || length < 1) ? 1 : length;
    const q = Array.from({length}, () => Promise.resolve());
    let index = 0;
    const add = cb => {
        index = (index + 1) % length;
        return (q[index] = q[index].then(() => cb()));
    };
    return add;
};

// demo usage

const q = multiQueue(10);

let inFlight = 0;
let maxInFlight = 0;
const promiseFunction = (i) => {
  	inFlight++;
    maxInFlight = Math.max(inFlight, maxInFlight);
    const obj = {inFlight, maxInFlight, i};
    return new Promise(resolve => {
        setTimeout(() => {
            inFlight--;
            resolve(Object.assign(obj, {t:performance.now()}));
        }, 10 );
    })
};

for (let i = 0; i < 40; i++) {
    q(() => promiseFunction(i)).then(v => console.log(JSON.stringify(v)));
}

可以看到最多有 10 个“inFlight”请求

【讨论】:

    【解决方案2】:

    这样的事情怎么样?如果你构造你的 queuefunctions 中的 Array 返回一个 Promise 你可以将 splice 分块出来并用 Promise.all 处理每个块。

    const fakePromise = (id) => {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log(`Resolving promise ${id}`)
          resolve(id)
        }, 100)
      })
    }
    
    const queue = Array(100).fill().map((_, i) => {
      return () => fakePromise(i)
    })
    
    const batchProcessPromises = (promises, batchSize) => {
      if (promises && promises.length) {
        return Promise.all(
          promises.splice(0, batchSize)
            .map(promise => promise())
        )
          .then(() => {
            console.log('Batch complete')
            return batchProcessPromises(promises, batchSize)
          })
      }
      console.log('Batch complete')
      return Promise.resolve()
    }
    
    batchProcessPromises(queue, 10)
      .then(() => {
        console.log('Time to get one with my day')
      })
    

    你打算如何构建你的所有承诺?此函数会影响原始队列,因此您需要确保传入batchProcessPromises 的数组不被共享。为了解决这个问题,您可以像这样使用扩展运算符

    batchProcessPromises([...queue], 10)
      .then(() => {
        console.log('Time to get one with my day', queue)
      })
    

    在这里提琴https://jsfiddle.net/stwilz/2bpdcxo6/24/

    【讨论】:

    • 如果你有一个 Promise 数组,那么它们已经被启动了。 Promise.all'ing 他们分批不会延迟他们的启动。它们都将同时运行。
    • 这是一个很好的观点@Cully!但是我提供的示例仍然只为提供的批处理运行Promise.all,而不是为队列(.map(promise =&gt; promise()))创建的 100 个承诺。我相信解决了所提出的问题,对吗?
    • Promise.alling 一次只接受 10 个承诺并不重要。一旦创建了 Promise,它们就会运行。因此,如果您在数组中创建 100 个 promise,它们都会开始运行(例如,当您创建 queue 变量时)。当您运行 Promise.all 时,它们不会启动。 Promises 热切地评估。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-25
    • 2017-07-25
    • 1970-01-01
    • 2022-12-11
    • 2020-02-17
    • 1970-01-01
    相关资源
    最近更新 更多