【问题标题】:Problems with nested async functions (async waterfall in async series)嵌套异步函数的问题(异步系列中的异步瀑布)
【发布时间】:2018-10-28 08:06:46
【问题描述】:

请对此有所帮助,我是 nodejs 新手,这是一个常见问题,我在这里尝试了其他帖子中的示例。我在最后一个函数中遇到了问题。

我正在尝试:

  1. 检查 data.json 是否存在并使用 async.waterfall 的一些数据创建它

function IfDataDontExistsCreate(callback)
{
    async.waterfall([ //If data dont exists
        function IfExistDataFile(callback) {
            fs.exists(path, function(exists){
                if(!exists)
                {
                    try {
                        const firstDataFile = {"readedPosts":{"id": []}};
                        const json = JSON.stringify(firstDataFile, null, 2);
                        callback(null, json);
                    } catch (error) {
                        callback(error);
                    }
                    
                }
            }
        )},
        function CreateDataFile(json ,callback) {
            fs.writeFile(path, json, function (err) {
                if(err) callback(err);
            })
        }
    ], function (err, callback) {
        if(err) throw err;
    });

    callback(null, callback);
}
  1. 读取 data.json,获取数据,添加一些信息并使用 async.waterfall 保存 data.json

function AppendtoDataFile(info, callback)
{
    async.waterfall([
        function ReadGetData(callback) {
            fs.readFile(path, (err, data) => {
                if(err) throw err;
                let datajson = JSON.parse(data.toString());
                datajson.readedPosts.id.push(info.toString()); //Add info
                callback(err, datajson)
            })
        },
        function WriteDataFile(data, callback) {
            const writeData = fs.writeFile(path, JSON.stringify(data, null, 2), function (err) {
                if(err) throw err;
                callback(err);
            })
        }
    ], function(err, callback)
    {
        if(err) throw err;
    });

    callback(null, callback);
}
  1. 使用 async.series 加入函数

function AddPostID(postID, callback)
{
    async.series({
        one: function (callback) {
            IfDataDontExistsCreate(function () {
                callback(null, "DataFile Created");
            });
        },
        two: function (callback) {
            AppendtoDataFile(postID, function () {
                callback(null, "PostID added to Datafile");
            });
        }
    }),
    function (err, results) {
        if(error) throw err;
        console.log(results);
    }
}

【问题讨论】:

  • 这正是 promises 被发明的原因。它们为链接、嵌套或分支异步操作创建了一个更加健全的机制。与await 一起使用时效果更好。
  • 阅读你的代码,你错过了多个回调,或者多次调用同一个......正如@jfriend00所说,你应该使用承诺。
  • 嗯,但使用的模块与回调函数和这些东西一起工作..
  • 是的,当然可以,但是既然我们现在得到了承诺,为什么不使用它们。看看我的回答,我将您的代码移植到了 Promise 中。如果您有任何疑问,请告诉我。

标签: javascript json node.js asynchronous async.js


【解决方案1】:

由于@Raeesaa 已经回答了您的具体问题, 我正在使用 promises 和 async/await 提供替代方案,使代码更具可读性和简洁

首先,你可以避免 fs.exists 使用 fs.writeFilewx 标志:

'wx' - 类似于 'w' 但如果路径存在则失败。


'use strict';

const fs = require('fs');
const { promisify } = require('util');

const writeFile = promisify(fs.writeFile);
const readFile = promisify(fs.readFile);

const path = '/tmp/foo.json';

async function IfDataDontExistsCreate() {
    const firstDataFile = {
        readedPosts: {
            id: []
        }
    };

    const json = JSON.stringify(firstDataFile, null, 2);

    try {

        await writeFile(path, json, { flag: 'wx' });
    } catch(e) {
        // If EEXIST means the file is already created, do nothing
        if(e.code !== 'EEXIST')
            throw e;
    }
}

async function AppendtoDataFile(info) {

    const data = await readFile(path, 'utf8');

    let datajson = JSON.parse(data);
    datajson.readedPosts.id.push(info.toString()); // Add info

    return writeFile(path, JSON.stringify(datajson, null, 2));
}

async function AddPostID(postID) {

    // Wait until the file is created
    await IfDataDontExistsCreate();
    console.log('DataFile Created');

    // We append after the file has been created
    await AppendtoDataFile(postID);
    console.log('PostID added to Datafile');

    return true;
}

AddPostID(5)
  .then(res => console.log('Done!'))
  .catch(err => console.error(err));

【讨论】:

  • 为什么用const { promisify } = require('util'); 而不是const promisify = require('util').promisify;?我知道解构是最新的小玩意儿,但为什么只使用一个属性呢?
  • 老实说,我是在我打开的一个项目中编写的,其中 eslint 唠叨着解构,所以我顺其自然。不过还是更短。
【解决方案2】:

我不确定您所面临的确切问题,但我确实在您的代码中看到了问题。函数IfDataDontExistsCreateAppendtoDataFile 中的callback 在异步瀑布完成执行之前被调用。

从 async.waterfall 的最终回调中调用 callback(err, null) 并从两个函数中删除最后一行,即 callback(null, callback) 应该可以为您解决问题。

【讨论】:

    猜你喜欢
    • 2015-07-18
    • 2020-09-06
    • 2014-05-09
    • 2016-08-18
    • 2019-01-02
    • 2023-03-15
    • 2018-11-13
    • 2012-10-12
    相关资源
    最近更新 更多