简体   繁体   English

具有已解决的Promise值的Node Promise返回对象

[英]Node Promise return object with value of resolved promise

I have some code below that will return all files in a directory with certain keys and values. 我下面有一些代码,这些代码将返回具有某些键和值的目录中的所有文件。 One of those keys I want to be isDirectory with a boolean value. 我想成为的键之一是具有布尔值的isDirectory。

The code below works just fine, but I was wondering if there was a way to remove the Promise.all/iterating over promises and instead pushing the resolved value of the stat.isDirectory() to my files objects directly in my map. 下面的代码工作正常,但是我想知道是否有一种方法可以删除Promise.all /迭代promise,而是将stat.isDirectory()的解析值直接推到我的地图中的文件对象中。

My solution I tried but failed: 我尝试但失败的解决方案:

I tried something like this: 我尝试过这样的事情:

isDirectory: fs.statAsync(path).then((stat) => stat.isDirectory())

And then do a Promise.all on all the isDirectory keys 然后对所有isDirectory键执行Promise.all

Working Code: 工作代码:

const Promise = require('bluebird'),
    os = require('os'),
    _ = require('lodash'),
    fs = Promise.promisifyAll(require('fs')),
    desktopPath = `${os.homedir()}/Desktop`;

let files = [];

return fs.readdirAsync(desktopPath)
    .then((filesName) => files = _.map(filesName, (fileName) => ({
        path: `${desktopPath}/${fileName}`,
        name: fileName,
        ext: _.last(fileName.split('.'))
    })))
    .then(() => Promise.all(_.map(files, (file) => fs.statAsync(file.path))))
    .then((stats) => _.forEach(stats, (stat, idx) => {
        files[idx].isDirectory = stat.isDirectory();
    }))
    .then(() => {
        console.log(files);
    })

Is there anyway to remove the Promise.all and _.forEach part at the end? 无论如何,最后是否要删除Promise.all和_.forEach部分? And instead do those actions in my map? 而是在我的地图中执行了这些操作?

You cannot remove the Promise.all entirely, because you want to wait for all files to finish before you use the final result. 您不能完全删除Promise.all ,因为您要等待所有文件完成后才能使用最终结果。 But you can do it all in one .then() call. 但是您可以在一个.then()调用中完成全部操作。

Because map is synchronous, it won't wait for the fs.statAsync to finish. 因为map是同步的,所以它不会等待fs.statAsync完成。 But you can create an array of promises of fs.statAsync that resolve with the final files object and the simply wait for all of them to complete by using Promise.all . 但是,您可以创建一个由fs.statAsync组成的承诺数组,这些承诺将与最终文件对象一起解析,并通过使用Promise.all来简单地等待所有这些对象完成。

A verbose version with some comments for clarification: 带有一些注释的详细版本:

fs.readdirAsync(desktopPath)
  .then(fileNames => {
    // Array of promises for fs.statAsync
    const statPromises = fileNames.map(fileName => {
      const path = `${desktopPath}/${fileName}`;
      // Return the final file objects in the promise
      return fs.statAsync(path).then(stat => ({
        path,
        name: fileName,
        ext: _.last(fileName.split(".")),
        isDirectory: stat.isDirectory()
      }));
    });
    // Promise.all to wait for all files to finish
    return Promise.all(statPromises);
  })
  .then(finalFiles => console.log(finalFiles));

And the compact version: 精简版:

fs.readdirAsync(desktopPath)
  .then(fileNames => Promise.all(
    fileNames.map(fileName =>
      fs.statAsync(`${desktopPath}/${fileName}`).then(stat => ({
        path: `${desktopPath}/${fileName}`,
        name: fileName,
        ext: _.last(fileName.split(".")),
        isDirectory: stat.isDirectory()
      })))
  ))
  .then(finalFiles => console.log(finalFiles));

Assuming you're using the latest Node - you can async/await , put async before your function definition and do: 假设您使用的是最新的Node-您可以async/await ,将async放在函数定义之前,然后执行以下操作:

const fileNames = await fs.readdirAsync(desktopPath);
const files = await Promise.map(fileNames, fileName => Promise.props({
  path: `${desktopPath}/${fileName}`,
  name: fileName,
  ext: fileName.split('.').pop(),
  isDirectory: fs.statAsync(`${desktopPath}/${fileName}`);
})));
console.log(files);
return files;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM