Nodejs Async的使用,为何这样写实现不了顺序执行?

Nodejs Async的使用,为何这样写实现不了顺序执行?

async.series(
[
function(callback){
writeLog(callback);
},
function(callback){
readLog(callback);
},
function(callback){
funcEnd(res, callback);
}
]
);

想顺序执行这三个方法,但是总是并发执行,是不是哪里写的不对呢?

function writeLog(callback){
fs.openSync(qpage,'w',0666);
for (var i = 1; i <= cnt; i++ ) {
    client.hgetall(i, function(err, obj) {
        fs.appendFileSync(qpage, "<br />" +util.inspect(obj), encoding='utf8');
    });
}
callback(null);}

function readLog(callback){
query = fs.readFileSync(qpage, 'utf8');
callback(null);}

function funcEnd(res, callback){
res.end(query, 'utf8');
callback(null);}

6 回复

在Node.js中使用async库进行异步操作时,如果想要确保函数按顺序执行,必须确保每个函数在完成其任务后正确地调用回调函数。从你提供的代码来看,问题在于writeLog函数中的异步操作(fs.appendFileSync)没有正确处理,导致callback被提前调用。

示例代码

const async = require('async');
const fs = require('fs');
const util = require('util');

// 假设client是一个已经定义好的客户端对象
const client = {}; // 请根据实际情况替换
const qpage = 'log.txt';
const cnt = 5;

function writeLog(callback) {
    fs.open(qpage, 'w', 0o666, (err, fd) => {
        if (err) return callback(err);

        const write = () => {
            if (cnt > 0) {
                client.hgetall(cnt, (err, obj) => {
                    if (err) return callback(err);
                    fs.appendFile(fd, `<br />${util.inspect(obj)}`, (err) => {
                        if (err) return callback(err);
                        cnt--;
                        write(); // 递归调用直到所有数据都写入
                    });
                });
            } else {
                fs.close(fd, (err) => {
                    if (err) return callback(err);
                    callback(null); // 所有操作完成后调用callback
                });
            }
        };

        write();
    });
}

function readLog(callback) {
    fs.readFile(qpage, 'utf8', (err, data) => {
        if (err) return callback(err);
        query = data;
        callback(null);
    });
}

function funcEnd(res, callback) {
    res.end(query, 'utf8');
    callback(null);
}

async.series([
    (callback) => writeLog(callback),
    (callback) => readLog(callback),
    (callback) => funcEnd(res, callback)
]);

解释

  1. 异步操作writeLog函数中,fs.appendFile是一个异步操作,不能直接使用同步版本fs.appendFileSync,因为它会阻塞事件循环。
  2. 递归写入:为了确保所有的hgetall操作都完成后再关闭文件描述符,我们使用递归来处理每次的写入操作。
  3. 顺序执行:通过将每个异步操作封装在一个函数中,并在该函数中调用callback来通知async.series该操作已完成,从而保证了操作的顺序执行。

以上代码确保了writeLogreadLogfuncEnd这三个函数能够按顺序执行。


你的业务代码都是同步执行的啊

仅仅几个需求是,毕竟还是因为并发才选择的Node

目测没什么问题。。。。应该是顺序执行的吧

哦,发现一个问题了 client.hgetall,这个是异步的还是同步的?如果是异步的话, 就会有问题

你的问题在于writeLog函数中的client.hgetall操作是异步的,但你使用的是fs.openSyncfs.appendFileSync这两个同步的方法。async.series确实可以保证函数按顺序调用,但由于writeLog内部的异步操作(client.hgetall),writeLogcallback可能在所有异步操作完成之前就被调用了。

为了确保writeLog内的异步操作完成后再调用callback,你可以使用async.each或返回一个Promise来处理。以下是使用回调风格改写的示例:

const async = require('async');

async.series([
    function(callback) {
        writeLog(callback);
    },
    function(callback) {
        readLog(callback);
    },
    function(callback) {
        funcEnd(res, callback);
    }
]);

function writeLog(callback) {
    fs.open(qpage, 'w', 0o666, (err, fd) => {
        if (err) return callback(err);
        let i = 1;
        const nextIteration = () => {
            if (i > cnt) return callback(null);
            client.hgetall(i++, (err, obj) => {
                if (err) return callback(err);
                fs.appendFile(fd, "<br />" + util.inspect(obj), 'utf8', err => {
                    if (err) return callback(err);
                    nextIteration();
                });
            });
        };
        nextIteration();
    });
}

function readLog(callback) {
    fs.readFile(qpage, 'utf8', (err, data) => {
        if (err) return callback(err);
        query = data;
        callback(null);
    });
}

function funcEnd(res, callback) {
    res.end(query, 'utf8');
    callback(null);
}

这里writeLog函数中通过递归方式确保每个hgetall操作完成后才继续下一个迭代。这样可以保证callback只在所有异步操作完成后被调用,从而保证async.series中其他函数按顺序执行。

回到顶部