Nodejs 异步事件中如何在闭包外打印出闭包的结果

Nodejs 异步事件中如何在闭包外打印出闭包的结果

var a = [1,2,3],
b = new Array();
a.forEach(function(each){
fs.readFile(‘test.html’,function(){
b[b.length] = each;
})
})
console.log(b);//打印为[]

我希望在b被赋值后被打印出来,请问代码应该怎么改?

8 回复

要解决这个问题,我们需要理解异步操作(如文件读取)的特点。在你的代码中,fs.readFile 是一个异步函数,这意味着它不会立即执行完毕并返回结果。因此,在 forEach 循环中调用 fs.readFile 后,console.log(b) 会立即执行,而此时 fs.readFile 的回调函数可能还未执行完成,所以 b 还没有被正确赋值。

为了确保在所有异步操作完成后才打印 b,我们可以使用 Promiseasync/await 来更好地控制异步流程。下面是两种方法的示例:

方法一:使用 Promises

const fs = require('fs');
const readFile = (filename) => {
    return new Promise((resolve, reject) => {
        fs.readFile(filename, (err, data) => {
            if (err) reject(err);
            else resolve(data);
        });
    });
};

const a = [1, 2, 3];
const b = [];

const promises = a.map(async (each) => {
    const data = await readFile('test.html');
    b.push(each);
});

Promise.all(promises).then(() => {
    console.log(b); // 打印为 [1, 2, 3]
});

方法二:使用 async/await

const fs = require('fs');

async function processArray() {
    const a = [1, 2, 3];
    const b = [];
    
    for (let each of a) {
        const data = await new Promise((resolve, reject) => {
            fs.readFile('test.html', (err, data) => {
                if (err) reject(err);
                else resolve(data);
            });
        });
        b.push(each);
    }
    
    console.log(b); // 打印为 [1, 2, 3]
}

processArray();

在这两个示例中,我们首先将 fs.readFile 封装成一个返回 Promise 的函数,这样就可以使用 await 关键字来等待每个文件读取操作完成。Promise.all 方法用于等待所有 Promise 完成,确保在所有异步操作都完成后才打印数组 b

通过这种方式,你可以确保在异步操作完成后正确地打印出 b 的内容。


fs.readFile 是异步…

还是不懂怎么解决,我希望获取到b = [1,2,3]

var async = require('async');

var fs = require('fs');

var a = [1,2,3],

    b = new Array();



async.forEach(a, function(each, cb){

	fs.readFile('test.html', function(){

		b[b.length] = each; 

		cb();

	});

},function(){

	console.log(b)

});
var a = [1,2,3];
var b = new Array();
async.forEach(a, function(each, cb){
    fs.readFile('test.html', function(){

        b[b.length] = each;

        cb(null,each);

    });

},function(err,results){

    console.log(results);

});

我想用上面这种方式输出,为什么得到的results未定义?

var nodeModulePath = path.join(__dirname, 'node_modules')
    , nodeModules = fs.readdirSync(nodeModulePath);
    , dependencies = {};   
    , emitter = new event.EventEmitter();
    , num = 0;
    , datetime = Date.now();

_.each(nodeModules, function(nodeModule) {
    var jsonPath = path.join(nodeModulePath, nodeModule, 'package.json');

    fs.readFile(jsonPath, function(err, data) {     //回调是在NodeJS 执行 所以不用担心num同步累加
        num ++;
        if(err) return;

        var packageJSON = JSON.parse(data);

        dependencies[packageJSON.name] = packageJSON.version;
        if(num == nodeModules.length) {
            emitter.emit('end', null, null);
        }

    });

});

emitter.on('end', function() {

    console.log(Date.now() - datetime);

    fs.readFile('./test.json', function(err, data) {
        if(err) return

        var rootJSON = JSON.parse(data);

        _.extend(rootJSON, {dependencies: dependencies});

        fs.writeFile('./test.json', JSON.stringify(rootJSON), function(err) {
            if(err) console.log('fialuer: %s', err);
            else console.log('success');
        });

    });
});

昨晚也碰到这个问题,设置了个计数器 遍历结束触发,EventEmitter 回调函数就行了 这个看个人需求 我执行的时候耗时平均 4ms

而同样的例子使用async 耗时平均18ms

挺好的,不同的思路。学习

在 Node.js 中处理异步操作时,闭包中的异步代码可能还未完成就执行了闭包外的代码。这会导致你期望的结果(如 b 数组)没有正确赋值。你可以使用回调函数或 Promises 来确保异步操作完成后再执行后续逻辑。

以下是一个使用回调函数的示例:

var fs = require('fs');
var a = [1, 2, 3];
var b = [];

function processArray(array, callback) {
    var count = 0;
    array.forEach(function (each) {
        fs.readFile('test.html', function () {
            b[b.length] = each;
            count++;
            if (count === array.length) {
                callback(b);
            }
        });
    });
}

processArray(a, function (result) {
    console.log(result); // 在这里打印结果
});

在这个例子中,我们定义了一个 processArray 函数,它接受一个数组和一个回调函数作为参数。当所有文件读取完成后,会调用传入的回调函数,并传递最终结果。

如果你熟悉 Promises,可以考虑使用 Promise 或 async/await 语法来简化代码结构。以下是使用 Promises 的示例:

const fsPromises = require('fs').promises;

async function processArray(array) {
    for (let each of array) {
        await fsPromises.readFile('test.html');
        b.push(each);
    }
    return b;
}

processArray(a)
    .then(result => console.log(result)) // 在这里打印结果
    .catch(err => console.error(err));

在这个例子中,我们使用了 fs.promises.readFile 方法将 fs 模块转换为返回 Promise 的形式。然后我们使用 async/await 语法来确保每个文件读取操作完成后才进行下一个操作。最后,我们在 processArray 调用后使用 .then() 来处理结果。

回到顶部