Javascript 为什么在reduce期间没有为推送到原始数组中的项调用Array.reduce函数?

Javascript 为什么在reduce期间没有为推送到原始数组中的项调用Array.reduce函数?,javascript,arrays,reduce,Javascript,Arrays,Reduce,给定以下代码: const ports = [null,3001]; function getPort(port) { return new Promise((resolve, reject) => { // setTimeout to simulate getting port from OS setTimeout(() => { if(port < 3010) { return reject(); } return

给定以下代码:

const ports = [null,3001];

function getPort(port)
{ return new Promise((resolve, reject) =>
  { // setTimeout to simulate getting port from OS
    setTimeout(() =>
    { if(port < 3010)
      { return reject();
      }
      return resolve();
    }, 2000);
  });
}

ports.reduce(async (acc, port, index) =>
{ if(!port)
  { return;
  }

  try
  {
    const avail = await getPort(port);
    return port;
  }
  catch(avail)
  { ports.push(++port);
  }
});
const-ports=[null,3001];
函数getPort(端口)
{返回新承诺((解决、拒绝)=>
{//setTimeout模拟从操作系统获取端口
设置超时(()=>
{if(端口<3010)
{return reject();
}
返回resolve();
}, 2000);
});
}
端口.reduce(异步(acc、端口、索引)=>
{如果(!端口)
{返回;
}
尝试
{
const avail=等待获取端口(端口);
返回端口;
}
捕获(有效)
{ports.push(++端口);
}
});
为什么只为元素
null
3001
调用reduce函数,而不调用
3002
,即使在
reduce
调用结束时,数组
端口
等于
[null,3001,3002]

在最后一个reduce调用完成之前,原始数组已经有了一个新元素,那么为什么不为该元素调用它呢

代码的目的是尝试从给定的数量和增量开始查找可用端口,直到找到一个,或者达到上限

还有其他方法可以做到这一点,但是
reduce
方法似乎是最简洁的,直到我遇到了这个死胡同

因为:

在第一次调用
callbackfn
之前设置
reduce
处理的元素范围。
callbackfn
在调用reduce开始后附加到数组的元素将不会被
callbackfn
访问。如果数组的现有元素发生更改,则传递到
callbackfn
的值将是
reduce
访问它们时的值;在调用
reduce
开始之后和被访问之前删除的元素不会被访问

(我的重点)

但另外,由于回调是一个
async
函数,在推送数组之前使用
getPort
上的
wait
,因此
reduce
调用在对
push
进行任何调用之前完成
reduce
同步执行其工作,即使您将
async
函数交给它
async
函数返回承诺(如果您查看,第二次回调上的
acc
将是一个承诺)

代码的目的是尝试从给定的数量和增量开始查找可用端口,直到找到一个,或者达到上限

一个简单的循环会…更简单:

async function findPort(start, max) {
    for (let port = start; port < max; ++port) {
        try {
            await getPort(port);
            return port;
        } catch (e) {
            // keep looking
        }
    }
    throw new Error(`No available port found starting at ${start} and stopping before ${max}`);
}
异步函数findPort(开始,最大值){ 用于(让端口=开始;端口<最大值;++端口){ 试一试{ 等待getPort(端口); 返回端口; }捕获(e){ //继续找 } } 抛出新错误(`没有找到从${start}开始并在${max}之前停止的可用端口'); } 实例:

函数getPort(端口){
返回新承诺((解析,拒绝)=>{//setTimeout以模拟从操作系统获取端口
设置超时(()=>{
如果(端口<3010){
返回拒绝();
}
返回resolve();
}, 200);
});
}
异步函数findPort(开始,最大值){
用于(让端口=开始;端口<最大值;++端口){
试一试{
等待getPort(端口);
返回端口;
}捕获(e){
//继续找
}
}
抛出新错误(`没有找到从${start}开始并在${max}之前停止的可用端口');
}
(异步()=>{
试一试{
log(“尝试3001到3020”);
let port=wait findPort(30013020);
log(`Got port${port}`);
}捕获(e){
错误(`Failed:${e}`);
}
试一试{
log(“尝试3001到3009”);
let port=wait findPort(3001309);
log(`Got port${port}`);
}捕获(e){
错误(`Failed:${e}`);
}
})();因为:

在第一次调用
callbackfn
之前设置
reduce
处理的元素范围。
callbackfn
在调用reduce开始后附加到数组的元素将不会被
callbackfn
访问。如果数组的现有元素发生更改,则传递到
callbackfn
的值将是
reduce
访问它们时的值;在调用
reduce
开始之后和被访问之前删除的元素不会被访问

(我的重点)

但另外,由于回调是一个
async
函数,在推送数组之前使用
getPort
上的
wait
,因此
reduce
调用在对
push
进行任何调用之前完成
reduce
同步执行其工作,即使您将
async
函数交给它
async
函数返回承诺(如果您查看,第二次回调上的
acc
将是一个承诺)

代码的目的是尝试从给定的数量和增量开始查找可用端口,直到找到一个,或者达到上限

一个简单的循环会…更简单:

async function findPort(start, max) {
    for (let port = start; port < max; ++port) {
        try {
            await getPort(port);
            return port;
        } catch (e) {
            // keep looking
        }
    }
    throw new Error(`No available port found starting at ${start} and stopping before ${max}`);
}
异步函数findPort(开始,最大值){ 用于(让端口=开始;端口<最大值;++端口){ 试一试{ 等待getPort(端口); 返回端口; }捕获(e){ //继续找 } } 抛出新错误(`没有找到从${start}开始并在${max}之前停止的可用端口'); }
实例:

函数getPort(端口){
返回新承诺((解析,拒绝)=>{//setTimeout以模拟从操作系统获取端口
设置超时(()=>{
如果(端口<3010){
返回拒绝();
}
返回resolve();
}, 200);
});
}
异步函数findPort(开始,最大值){
用于(让端口=开始;端口<最大值;++端口){
试一试{
等待getPort(端口);
返回端口;
}捕获(e){
//继续找
}