【问题标题】:assigning to array at different times yields different results在不同时间分配给数组会产生不同的结果
【发布时间】:2018-01-29 15:15:46
【问题描述】:

我有这两个不同的代码,它们略有不同但产生不同的结果:

(async () => {
  const results = new Array(concurrentBrowsers).fill({});
  const browsers = [];
  for (let index = 0; index < concurrentBrowsers; index++) {
    browsers.push(
      (async function() {
        let i = index;
        const browser = await puppeteer.launch({ headless });
        const page = await getNewPage({ browser });
        results[i].loginPage = await timer(actions.loginPage, { page }); // <---- this line
        results[i].homePage = await timer(actions.homePage, {
          page,
          username,
          password
        });
        console.log(i, results[i]);
        browser.close();
      })()
    );
  }
  await Promise.all(browsers);
})();

结果

1 { loginPage: 2.924, homePage: 19.939 }
2 { loginPage: 2.924, homePage: 21.388 }
3 { loginPage: 2.924, homePage: 21.122 }
0 { loginPage: 2.924, homePage: 21.305 }
4 { loginPage: 2.924, homePage: 21.6 }

还有一个:

(async () => {
  const results = new Array(concurrentBrowsers).fill({});
  const browsers = [];
  for (let index = 0; index < concurrentBrowsers; index++) {
    browsers.push(
      (async function() {
        let i = index;
        const browser = await puppeteer.launch({ headless });
        const page = await getNewPage({ browser });
        let loginPageTime = await timer(actions.loginPage, { page }); // <---- this line
        let homePageTime = await timer(actions.homePage, {
          page,
          username,
          password
        });
        results[i].loginPage = loginPageTime;
        results[i].homePage = homePageTime;
        console.log(i, results[i]);
        browser.close();
      })()
    );
  }
  await Promise.all(browsers);
})();

结果

2 { loginPage: 3.291, homePage: 17.911 }
4 { loginPage: 3.226, homePage: 18.949 }
1 { loginPage: 3.047, homePage: 22.619 }
0 { loginPage: 3.291, homePage: 24.508 }
3 { loginPage: 3.059, homePage: 26.391 }

第一个代码有一个错误,似乎loginPage 结果总是取自最后一次迭代,并且如您所见,在所有迭代中都设置为相同的值。

唯一的区别是我在第一个示例中将计时器的结果分配给results[i].loginPage,在第二个示例中分配给loginPageTime

有人能解释一下这个区别吗?

谢谢

【问题讨论】:

  • FWIW,异步函数是 ES2017 特性。

标签: javascript arrays ecmascript-2017


【解决方案1】:

事实上,两个代码变体都存在相同的问题,但是第二个代码块并没有显示出什么问题:

const results = new Array(concurrentBrowsers).fill({});

这会创建 一个(!) 空对象并将其分配给 all 数组条目。您对该对象所做的任何更改都将通过所有数组条目看到,因为它们都引用同一个对象。

您在第一个版本中看到不一致的原因是,在同一迭代中的两个 await 表达式之间发生了其他分配,而第二个代码版本直到之前才进行分配console.log

您可以按如下方式正确初始化results

const results = Array.from(new Array(concurrentBrowsers), _ => ({}));

【讨论】:

  • @Michael 它在每个数组项中都是同一个对象.. 例如.. 就像你这样做.. var a = {x:1}, b = a; b.y = 2; a & b 都等于 {x:1,y:2} IOW: javascript 中的对象是引用基于,当你做a = b你复制参考,而不是它的价值。
  • @Keith 如果是这样,为什么 loginPage 一样,而 homePage 不一样?
  • @Bob 因为请求是异步的,并且放置在 Promise.All 中,.. 然后他在进行控制台日志记录,这是一个时间问题。他的结果都将取决于承诺何时解决。如果他在 Promise.all 之后执行console.log(results),您会看到所有值都相同。
  • @trincot 这很聪明,确实是问题所在。我仍然不明白为什么这两种情况的结果不同
  • 也许它有助于理解是否在代码的第一个版本中(有问题的results 初始化)你在两个等待之间放置一个console.log(i, results[i]):然后你会注意到那个记录的值通常与您从下面几行之后的console.log 获得的输出不同(对于相同的i)。这是因为第二个await 将允许其他承诺解析并分配给loginPage,这将覆盖您刚刚记录的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-05
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 2012-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多