【问题标题】:Problem with Promise.all() and .map, unexpected resultsPromise.all() 和 .map 的问题,意外结果
【发布时间】:2021-06-06 11:29:35
【问题描述】:

我已经阅读了有关承诺的所有内容,我从多个线程测试了多个解决方案,但我仍然无法让它工作

我正在尝试遍历文件夹中的文件,获取 xml 内容,使用 xml-js 模块将其转换为 js 对象,然后将它们添加到数组中。 这是我最后一次尝试(大约 30 次中的一次)

fs.readdir(folderPath, async(err, files) => {
    let xmlArray = await Promise.all(
        files.map((file) => {
            fs.readFile(filePath, 'utf8', async(err, data) => {
                return await xmljs.xml2js(data , {compact : true).RequestFileHatasDM;
            })
        })
    )
    console.log(xmlArray);
})

我错过了什么? 我认为 readdir 被调用,然后回调返回,这就是我等待 Promise.all 的地方,然后使用 .map 迭代所有内容并返回值,该值应该(?)返回并承诺解决。

然后在一切都解决之后,它才应该继续到console.log(),但由于某种原因,当我运行服务器时它立即跳转到console.log(),好像所有的promise都已经解决了!

将 console.log() 放入 readFile 方法时,它仍在运行。

我很困惑,谁能指出我的错误?

【问题讨论】:

    标签: node.js dictionary asynchronous promise


    【解决方案1】:

    这里有几件事。 First Promise.all 接受一系列你没有给它的承诺。在您的 files.map 中,您不会在该地图回调函数中返回任何内容。所以试试这个:

    files.map((file) => {
            return fs.readFile(filePath, 'utf8', async(err, data) => {
                return await xmljs.xml2js(data , {compact : true).RequestFileHatasDM;
            })
        })
    

    此外,当您在异步函数中返回承诺时,您可以这样做:

    return xmljs.xml2js()
    

    代替:

    return await xmljs.xml2js()
    

    很容易错过。我鼓励您设置一个调试环境,以便您可以单步执行该函数并观察代码中的不同值。它确实可以为您节省一些调试代码的时间。

    我喜欢 VSCodes 调试器:

    https://code.visualstudio.com/docs/nodejs/nodejs-debugging

    【讨论】:

    • 您好!我一直试图让它工作但无济于事,我尝试设置静态路径而不使用 readdir 并且承诺从未解决,当使用与上面相同的代码并添加 return 我仍然得到一个未定义的数组。 @Terry 的回答非常好,但我想让它在不使用 promisify 的情况下更好地理解承诺。你能详细说明你的答案吗?
    • 对不起,我实际上应该比我做的更多地审查我的答案。 @Terry 的回答是一个很好的解决方案。使用带有回调的 Promise 是两种不同的风格,并且会产生非常混乱的代码。像 readFile 这样的有前途的方法是一种很好的方式来保持它的风格。根据您使用的节点版本,您可以查看一下。 nodejs.org/docs/latest-v14.x/api/fs.html#fs_fs_promises_api 它只负责 promisify 部分。
    【解决方案2】:

    这种代码可能非常令人困惑。它可以更轻松地创建一个返回 Promise 并接受文件路径作为输入的函数。

    我们可以使用Util.Promisify 来创建fs.readFile 的promisified 版本,生成的代码更容易阅读,也更紧凑。

    然后我们可以在通过这个函数映射文件路径的结果上使用 Promise.all。

    例如:

    const fs = require('fs');
    const path = require('path')
    const xmljs = require('xml-js');
    const { promisify } = require ('util');
    
    const readFilePromise = promisify(fs.readFile);
    const readDirPromise = promisify(fs.readdir);
    
    // Replace as appropriate.
    const folderPath = 'test_dir';
    
    async function xmlFile2js(path) {
        const data = await readFilePromise(path, { encoding: 'utf-8'});
        return xmljs.xml2js(data, { compact: true});
    }
    
    async function readXmlFiles(folderPath) {
        try {
            const files = await readDirPromise(folderPath);
            const filePaths = files.map(file => path.join(folderPath, file));
            const promiseArray = filePaths.map(filePath => xmlFile2js(filePath));
            const xmlArray = await Promise.all(promiseArray);
            return xmlArray;
        } catch (err) {
            console.error("readXmlFiles: An error occurred:", err);
        }
    }
    
    async function testReadXmlFiles() {
        const xmlArray = await readXmlFiles(folderPath);
        console.log("testReadXmlFiles: xmlArray:", JSON.stringify(xmlArray, null, 4));
    }
    
    testReadXmlFiles();
    

    【讨论】:

    • 这个成功了!我了解代码,但如果您能指出原始代码中的错误,我会很高兴,因为我也想从错误中吸取教训
    • 我明白了!我现在遇到其他问题,我尝试将整个代码移动到一个名为 generateCompleteXmlFile 的单独异步方法中,然后在将文件添加到文件夹时从 server.js 调用它(使用监视)我将 console.log(xmlArray) 更改为 @987654325 @ 并等待它,但它不等待。知道为什么吗?看起来有点像这样:let result = await xmljs.generateCompleteXmlFile() then console.log(result) result is undefined
    • 我添加了一个回调到 generateCompleteXmlFile 并修复了它,但这是正确的做法吗?
    • 那么我将如何仅通过承诺解决这种情况?当我尝试await 像这样的let result = await xml2js.generateCompleteXmlFile() 并且下一行我做了console.log(result) 时,我几乎立即收到了undefined,它没有等待,我不知道为什么
    • 首先,感谢您抽出这么多空闲时间提供帮助!我已经尝试过你的方法,但由于某种原因,await 不起作用,console.log("testReadXmlFiles:...) 立即解决,undefined,这就是为什么我如此困惑并求助于回调
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    • 2013-07-10
    相关资源
    最近更新 更多