gpt4 book ai didi

javascript - 程序失败,因为readFile是异步的?

转载 作者:行者123 更新时间:2023-11-30 11:57:36 24 4
gpt4 key购买 nike

我正在尝试合并两个列表。 List1有681个法语动词,List2有681个翻译。
我正在使用javascript和node.js读取文件。
这是我的尝试:

    var frenchWords, englishWords, combinedList;
fs = require('fs')

// 1. read the french file

fs.readFile('frenchVerbsList.txt', 'utf8', function (err,data) {
if (err) {
return console.log("ERROR here!: " + err);
}
frenchWords = data.split('\n');
});

//read the english file

fs.readFile('englishVerbsList.txt', 'utf8', function (err,data2) {
if (err) {
return console.log("ERROR here!: " + err);
}
englishWords = data2.split('\n');
});

// 2. combine the lists
//*** it fails here, I'm guessing it's because the readFile operation hasn't finished yet.

var combinedList;
for(i=0; i<frenchWords.length; i++){
combinedList[i] = frenchWords[i] + ",,," + englishWords[i];
}
// 3. check the result

for(i=0; i<10; i++){
console.log(combinedList[i]);
}


非常感谢您的帮助,我这样做是为了让我的思想活跃:-)

最佳答案

您正确地认为fs.readFile()回调的异步性质引起了您的问题。

这些回调将在将来的不确定时间内调用,而其余的代码将继续运行。由于node.js的事件驱动设计,在您的其余代码完成执行之前,不会调用回调。因此,可以保证您将在使用englishWordsfrenchWords变量之前先尝试使用它们。

您有多种选择:

切换到fs.readFileAsync(在大多数情况下不推荐)

您可以切换到使用fs.readFileSync()。这是最简单的更改,因为您当前的控制流程将起作用。但是,通常不建议在node.js开发中使用它,因为它对服务器使用效率不高。如果此代码在服务器进程中,可以/应该在等待读取文件的同时保持做其他事情的能力,则fs.readFileSync()将破坏可伸缩性。如果这只是一次性脚本(不是已加载的服务器),则fs.readFileSync()可能会正常工作。但是,您可能应该学习使用异步操作正确编码的更好的“ node.js风格”等待(请参见以下选项)。

通过继续回调内部的流程来序列化操作

您可以使用嵌套序列化异步操作。这涉及仅在异步回调中继续处理逻辑。这样,您知道所需的结果可用于继续处理。看起来像这样:

const fs = require('fs')

// read the french file
fs.readFile('frenchVerbsList.txt', 'utf8', function (err, data) {
if (err) {
return console.log("ERROR here!: " + err);
}
var frenchWords = data.split('\n');

//read the english file
fs.readFile('englishVerbsList.txt', 'utf8', function (err, data2) {
if (err) {
return console.log("ERROR here!: " + err);
}
var englishWords = data2.split('\n');

// 2. combine the lists
var combinedList = [];
for (i = 0; i < frenchWords.length; i++) {
combinedList[i] = frenchWords[i] + ",,," + englishWords[i];
}

// 3. check the result
for (i = 0; i < 10; i++) {
console.log(combinedList[i]);
}
});
});


手动编写检查两个异步操作均已完成的检查

上面的serialize选项的缺点在于,它在开始下一个异步操作之前会等待第一个异步操作完成。这不是理想的,因为两个异步操作都可以并行运行(更快的最终结果)。以下所有选项都是并行运行异步操作并监视它们都完成时的不同方式,因此您可以触发最终处理。这是手动监视选项。在加载法语和英语单词的完成回调中,您检查另一个是否也已完成。如果是,则调用一个函数来处理结果。由于一次只能完成一个操作,因此只要没有错误,它们中的一个将第二秒完成,并将调用您的函数来处理结果:

var frenchWords, englishWords;
fs = require('fs')

// read the french file
fs.readFile('frenchVerbsList.txt', 'utf8', function (err, data) {
if (err) {
return console.log("ERROR here!: " + err);
}
frenchWords = data.split('\n');
if (frenchWords && englishWords) {
processResults();
}
});

//read the english file

fs.readFile('englishVerbsList.txt', 'utf8', function (err, data2) {
if (err) {
return console.log("ERROR here!: " + err);
}
englishWords = data2.split('\n');
if (frenchWords && englishWords) {
processResults();
}
});

function processResults() {

// combine the lists
var combinedList = [];
for (let i = 0; i < frenchWords.length; i++) {
combinedList[i] = frenchWords[i] + ",,," + englishWords[i];
}

// check the result
for (let i = 0; i < 10; i++) {
console.log(combinedList[i]);
}
}


使用ES6承诺监视您的异步操作

有了ES6,promise现在已成为Javascript规范的标准部分,它们是协调多个异步操作的绝佳方法,并且还使正确的错误处理(尤其是在复杂的情况下)更加简单。要在此处使用Promise,您首先要创建 fs.readFile()的“承诺版本”。这将是一个使用promise而不是普通回调的包装函数。然后,您可以使用 Promise.all()来协调两个异步操作的完成时间。

var fs = require('fs');
// promise wrapper
fs.readFileAsync = function(file, encoding) {
return new Promise(function(resolve, reject) {
fs.readFile(file, encoding, function(err, data) {
if (err) return reject(err);
resolve(data);
});
});
}

// common helper function
function readFileSplitWords(file) {
return fs.readFileAsync(file, 'utf8').then(function(data) {
// make split words be the fulfilled value of the promise
return data.split('\n');
});
}

var frenchPromise = readFileSplitWords('frenchVerbsList.text');
var englishPromise = readFileSplitWords('englishVerbsList.txt');
Promise.all([frenchPromise, englishPromise]).then(function(results) {
// combine the lists
var frenchWords = results[0], englishWords = results[1];
var combinedList = [];
for (i = 0; i < frenchWords.length; i++) {
combinedList[i] = frenchWords[i] + ",,," + englishWords[i];
}

// check the result
for (i = 0; i < 10; i++) {
console.log(combinedList[i]);
}
}, function(err) {
// handle an error here
});


使用Promise库扩展Promise功能

ES6 Promises非常强大,但是在使用某些第三方库添加的Promise时,它们具有非常有用的功能。我个人使用了Bluebird库。这是使用Bluebird库的前一个选项的外观:

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

// common helper function
function readFileSplitWords(file) {
return fs.readFileAsync(file, 'utf8').then(function(data) {
// make split words be the fulfilled value of the promise
return data.split('\n');
});
}

var frenchPromise = readFileSplitWords('frenchVerbsList.text');
var englishPromise = readFileSplitWords('englishVerbsList.txt');
Promise.all([frenchPromise, englishPromise]).spread(function(frenchWords, englishWords) {
// combine the lists
var combinedList = [];
for (i = 0; i < frenchWords.length; i++) {
combinedList[i] = frenchWords[i] + ",,," + englishWords[i];
}

// check the result
for (i = 0; i < 10; i++) {
console.log(combinedList[i]);
}
}, function(err) {
// handle an error here
});


这使用Bluebird的 Promise.promisifyAll()自动生成 fs库中所有方法的承诺版本(非常有用)。并且,它使用 .spread()方法而不是 .then()自动将两个结果分离为它们的命名参数。

使用更多扩展功能来处理文件名的任意数组

您还可以使用更多扩展的Bluebird功能,例如 Promise.map(),它处理一个数组,然后对所得的Promise执行 Promise.all()(上述代码是手动完成的)。这样,您就可以将文件名设置为任意语言的文件名的任意列表,并且可以在这方面使代码更通用:

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

// common helper function
function readFileSplitWords(file) {
return fs.readFileAsync(file, 'utf8').then(function(data) {
// make split words be the fulfilled value of the promise
return data.split('\n');
});
}

var files = ['frenchVerbsList.text', 'englishVerbsList.txt'];
Promise.map(files, readFileSplitWords).then(function(results) {
// results is an array of arrays where each sub-array is a language list of words
// combine the lists (assumes all word lists have the same length)
var combinedList = [];
var len = results[0].length;
// for each word in the first array
for (var i = 0; i < len; i++) {
// get all the other words in the same array position
var words = [];
for (var j = 0; j < results.length; j++) {
words.push(results[j][i]);
}
combinedList.push(words.join(',,,'));
}

// check the result
for (i = 0; i < 10; i++) {
console.log(combinedList[i]);
}
}, function(err) {
// handle an error here
});

关于javascript - 程序失败,因为readFile是异步的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37500766/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com