Сортировка массива возвращает массив из строя - PullRequest
1 голос
/ 07 октября 2019

Я сейчас так растерялся. Я потратил последний час и немного пытался отсортировать каталоги по дате их создания. Вот где я нахожусь:

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 выплевывает неупорядоченный массив.

Обещания являются новыми для меня, поэтому яне совсем уверен, что проблема связана с цепочкой обещаний, но все кажется хорошим до второго then.

Любая помощь будет принята с благодарностью.

1 Ответ

3 голосов
/ 07 октября 2019

Это цепочка обещаний: если цепь где-нибудь разорвется, она не сработает.

Похоже, вы смешиваете две формы стрелок: (params) => expression и (params) => { statements }. Все в вашем коде выразимо с первым, поэтому я пошел с этим. Если вы преобразуете в форму блока операторов, не забудьте return (что форма выражения делает неявно).

Поскольку вы не возвращаете обещания из блока операторов стрелки, следующее обещание несшитый с предыдущим, так что ожидания больше не происходят, и все выполняется гораздо более синхронно, чем предполагалось. Кроме того, если у вас есть несколько обещаний, вам нужно подождать, пока все они будут готовы выполнить, используя Promise.all. Это создаст обещание, что все подчиненные обещания выполнены, и вернет массив результатов подчиненных обещаний.

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 получает массив обещаний и обещает массив результатов этих обещаний, когда все они выполнены. Мы объединяем это в обещание отсортированного массива, а затем объединяем в обещание консольной регистрации массива.

РЕДАКТИРОВАТЬ: Я не уверен, но я не думаю, что Promise.all существует вЯдро Node.jsДля Node.js существует любое количество пакетов обещаний, которые включают Promise.all, почти любой из них подойдет (например, Bluebird ). Или вы можете реализовать его самостоятельно , это не так уж и много.

EDIT2: Можно также предложить вам переключиться на async / await, если это поддерживается в вашей среде. , поскольку это делает код намного более похожим на то, к чему вы привыкли. Тем не менее, некоторое понимание обещаний все еще необходимо, поскольку все эти обещания находятся под капотом. : 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();
...