Javascript 如何在特定条件下做出承诺?

Javascript 如何在特定条件下做出承诺?,javascript,promise,Javascript,Promise,我是JavaScript新手,我真的被关于承诺的文档弄糊涂了。 我在这里有一个例子,其中我有一批用户,对于每个用户,我执行一个异步函数,在该函数中,我对该用户进行一些计算,并将结果与用户一起添加到一个数组中。根据我从文档中了解到的情况,每次执行异步函数时,我都需要得到一个承诺,并将所有承诺添加到承诺列表中,在将结果数组传递给它时解析,如下所示: someFunction = () => { var promises = []; users.forEach(user =>

我是JavaScript新手,我真的被关于承诺的文档弄糊涂了。 我在这里有一个例子,其中我有一批用户,对于每个用户,我执行一个异步函数,在该函数中,我对该用户进行一些计算,并将结果与用户一起添加到一个数组中。根据我从文档中了解到的情况,每次执行异步函数时,我都需要得到一个承诺,并将所有承诺添加到承诺列表中,在将结果数组传递给它时解析,如下所示:

 someFunction = () => {
   var promises = [];
   users.forEach(user => {
       var promise = asyncFunction(user).callback(callBackValue => {
         // Run some checks and add the user to an array with the result
         if (checksAreGood) {
           usersArray.push({user: user, result: callBackValue});
         }
       });
       promises.push(promise);
   });
   return Promise.all(promises).then(() => Promise.resolve(matches));
 };
问题是:如果我正在遍历的用户数未知,并且我想将添加到数组中的用户数限制为20,如果且仅当用户数超过20,否则添加所有用户。换句话说,当阵列中满20个或更少的用户时,解决承诺问题。
这样做的目的是避免对给定的全部用户执行异步函数以优化性能。也就是说,如果我有1000个用户,我希望异步函数一直执行到数组满了20个为止。

第一个只搜索到20个用户的解决方案是遍历一个又一个用户:

虽然这工作“完美”,但它相当慢,因为它一次只处理一个请求。因此,相反的解决方案是一次运行所有请求,并在阵列已满时取消它们:

 async function someFunction(){
  const results = [];
  async function process(user){
    const result = await asyncFunction(user);
    if(!someChecksGood || results.length >= 20) return;
    results.push(result);
   }
   await Promise.all(users.map(process));
   return results;
 }
但是现在有大量不必要的请求,这些请求在之后被丢弃。为了改善这一点,可以通过“分块”请求将上述两种方法结合起来,这不会减少请求时间,因为dbs一次只能处理一定数量的请求,但好的是,我们可以在数组已满时停止处理,并且只处理“分块”的其余部分,因此,平均而言,它应优于上述两种解决方案:

  async function someFunction(){
    //Chunk the users
    const chunks = [], size = 5;
    for(var i = 0; i < users.length; i += size)
      chunks.push( users.slice(i, i + size));
    //the method to create the results:
    const results = [];
    async function process(user){
      const result = await asyncFunction(user);
      if(!someChecksGood || results.length >= 20) return;
      results.push(result);
    }
    //iterate over the chunks:
    for(const chunk of chunks){
      await Promise.all(chunk.map(process));
      if(results.length >= 20) break;
    }
    return results;
 }
异步函数someFunction(){
//将用户分块
常量块=[],大小=5;
对于(变量i=0;i=20)返回;
结果。推(结果);
}
//迭代块:
for(常量块中的块){
等待承诺.all(chunk.map(process));
如果(results.length>=20)中断;
}
返回结果;
}

您没有在promise数组中推送承诺。另外,我认为执行
users.slice(0,20)。forEach(…)
将起作用(仅在前20个用户上循环)@GuyWhoKnowsStuff不起作用,因为有时asyncFunctions检查条件可能失败,用户不会被添加到数组中。我想你可以做两件事。1) 在你首先验证的地方做一个循环,然后将前20个验证的部分切片,但这在所有情况下都是不可能的。但是2)您可以尝试
if(usersArray.length<20)usersArray.push(…)
假设您有30个用户,并且当您定义承诺时,将立即调用异步函数。因此,在代码中,同时调用30个异步函数。在结果返回之前,您不知道将通过多少个检查条件以及将返回多少用户。因此,您必须运行所有异步函数才能找到答案。如果您不想运行所有异步函数,则需要按顺序运行它们,并根据以前的结果决定是否运行下一个函数,但这样会慢得多。谢谢您的回答。第二个几乎就是我要找的。唯一的问题是,当数组长度>=20时,用户不会被推送到数组中。。。是的,那很好。。。但是,如果我有100个用户,异步函数将执行100次,这比实际需要的处理量要多。+1对于第三个版本。尽管第一个区块的大小最好是20+平均故障量。(失败的数量也可以用来计算第二块有多大)@ahmed第一段和第二段实际上只是第三段解释的一部分,这才是真正的答案;)@乔纳斯。是的,我可以看到:D。。。在我写评论后,我注意到了你的更新,所以我会检查它并让你知道know@JonasW. 我无意冒犯你的回答:)这是一个很好的回答,而且已经非常详细了。我认为答案不应该总是被提炼成复制粘贴的形式。我的评论更多是针对那些可能错过了可能的优化的人。通常,异步函数已经是对批处理的请求。
  async function someFunction(){
    //Chunk the users
    const chunks = [], size = 5;
    for(var i = 0; i < users.length; i += size)
      chunks.push( users.slice(i, i + size));
    //the method to create the results:
    const results = [];
    async function process(user){
      const result = await asyncFunction(user);
      if(!someChecksGood || results.length >= 20) return;
      results.push(result);
    }
    //iterate over the chunks:
    for(const chunk of chunks){
      await Promise.all(chunk.map(process));
      if(results.length >= 20) break;
    }
    return results;
 }