【问题标题】:Sorting Array Returns Array Out of Order排序数组返回无序数组
【发布时间】:2020-02-04 09:44:42
【问题描述】:

我现在很困惑。我花了最后一个小时尝试根据创建日期对目录进行排序。这是我所在的位置:

const
  fsPromises = require('fs').promises
let
  arr = []

fsPromises.readdir(rootPath, 'utf8')
.then((array)=>{

  array.forEach((dir)=>{
    console.log(dir) // executed last for some reason
    fsPromises.stat(`./Projects/${dir}`)
    .then((stats)=>{
      arr.push([stats.birthtimeMs, dir])
    })
  })

})
.then(()=>{
  arr = arr.sort((a,b)=>{
    Math.floor(a[0])-Math.floor(b[0])
  })
})
.then(console.log(arr))

我不知道为什么最后的 then 会吐出一个无序数组。

Promise 对我来说是新的,所以我不完全确定是不是 Promise 链导致了问题,但直到第二个 then 之前一切似乎都很好。

任何帮助将不胜感激。

【问题讨论】:

  • 尝试在第一个.then中添加console.log(arr))
  • 最后的.then() 应该是打印undefined,而不是一个数组。你应该先看到它的输出。
  • @mph85 在第一个then 中粘贴console.log 的问题在于fsPromises.stat 也是异步的。我对 Node、Electron、FS 和 Promises 完全陌生,所以这真的让我陷入了一个循环:(
  • @PatrickRoberts 哦该死,对不起。在我的代码中,我有let arr = [],你说得对,它出于某种原因首先运行。承诺的全部目的不是按顺序运行thens 吗?
  • @BugWhisperer 你不是在等待循环内创建的承诺。您应该将它们分组并等待它们在 Promise.all 中完成。之后,您的 then 将具有正确的值。

标签: arrays node.js sorting promise fs


【解决方案1】:

这是承诺链:如果链在任何地方都被破坏,它将无法工作。

您似乎混淆了两种箭头形式:(params) => expression(params) => { statements }。您的代码中的所有内容都可以用前者来表达,所以我同意了。如果您转换为语句块形式,请不要忘记 return(表达式形式隐含)。

因为你没有从箭头语句块返回承诺,下一个承诺不会缝合到前一个承诺,所以没有等待,事情的执行比预期的要同步得多。此外,如果您有多个 Promise,则需要使用 Promise.all 等到它们都准备好履行。它将创建一个所有子promise 都已完成的promise,并返回子promise 的结果数组。

fsPromises.readdir(rootPath, 'utf8')
.then(array => Promise.all(
    array.map(dir =>
        fsPromises.stat(`./Projects/${dir}`)
        .then(stats => [stats.birthtimeMs, dir])
    )
))
.then(arr =>
  arr.sort((a, b) =>
    Math.floor(a[0]) - Math.floor(b[0])
  )
)
.then(arr => console.log(arr))

(我没有检查这个,所以可能会有意外的龙。)

所以首先readdir 承诺一个文件数组。我们将映射这个数组,以便对于每个文件名,stat 对其统计数据做出承诺,并将其链接到元组的承诺中。所以array.map 现在返回一个元组承诺数组。 Promise.all 接收承诺数组,并在所有承诺完成后承诺这些承诺的结果数组。我们将其链接到有序数组的承诺中,然后将其链接到控制台记录数组的承诺中。

编辑:我不确定,但我认为 Node.js 核心中不存在 Promise.all。 Node.js 有许多 Promise 包确实包含 Promise.all,几乎任何一个都可以(例如 Bluebird)。或者,你可以implement it yourself,没那么大。

EDIT2:如果您的环境支持它,也可以建议您切换到async/await,因为它使代码与您习惯的代码更加相似。但是,仍然需要对 Promise 有一些了解,因为它是引擎盖下的所有 Promise。 :P

async function statDir() {
  let files = await fsPromises.readdir(rootPath, 'utf8');
  let stats = [];
  for (let file of files) {
    let stat = await fsPromises.stat(`./Projects/${file}`);
    stats.push([stat.birthtimeMs, file]);
  }
  stats.sort((a, b) =>
    Math.floor(a[0]) - Math.floor(b[0])
  );
  console.log(stats);
}
statDir();

【讨论】:

  • 酷。我可能宁愿自己实现它而不是包含另一个依赖项。我可能需要一些时间来消化所有这些,因为整个 Promise 概念对我来说都是非常新的,而且我盯着屏幕看太久了。
  • 哇,Promise.all 在您的第一个示例中确实有效。既然Node毕竟是JS,它不应该工作吗?或者是否有它不起作用的原因?
  • 哦,我想我记得旧版本...?或者是脑子放屁,谁知道呢。我想我应该删除那段。
  • async await 语法更加直观易懂。只是因为我不习惯承诺吗?哪种语法对您来说更直接?
  • 正如我所说,async/await 的创建是为了简化 Promise 语法并使其看起来几乎像同步代码。不过它仍然在处理 Promise,所以如果你不理解 Promise,很容易搞砸async/await
猜你喜欢
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多