在JavaScript / Node.js中,如何使用Async / Await为下面的代码返回带有a,b,c和d的placeName。
test.csv有c,d
var placeName = ["a","b"];
var csvFile = 'test.csv';
fs.readFile(csvFile, 'UTF-8', function(err, csv) {
$.csv.toArrays(csv, {}, function(err, data) {
for(var i=0, len=data.length; i<len; i++) {
console.log(data[i]); //Will print every csv line as a newline
placeName.push(data[i][0].toString());
}
});
console.log(placeName); //Inside the function the array show a,b,c,d
});
// Prints only a and b. Did not add c & d from the csv.
console.log(placeName);
await
运算符等待履行的承诺,并且只能在async
函数中使用 - 这些函数在调用时返回一个promise。因此,需要将更新地名编写为返回promise的函数。可以对所有操作使用单一承诺,但不建议:
function addNames(placeName, csvFile) {
return new Promise( (resolve, reject) => {
fs.readFile(csvFile, 'UTF-8', function(err, csv) {
if(err) {
reject(err);
}
else {
$.csv.toArrays(csv, {}, function(err, data) {
if( err) {
reject( err);
}
else {
for(var i=0, len=data.length; i<len; i++) {
console.log(data[i]); //print supplied data elements
placeName.push(data[i][0].toString());
}
}
resolve( placeName);
});
}
});
});
}
虽然未经测试,但这是基于发布的代码:输入placeName
数组已就地修改。如果满足,则将promise值设置为已修改的数组。但是......
请注意,代码变得更加缩进,添加了更多节点样式的回调操作?极端情况下这会导致称为“回调地狱”的情况 - 难以编写,无错误编译或维护。
删除嵌套回调是承诺的设计目标之一,可以通过单独的promisifying操作来实现。以下示例不仅分离读取和解码,还将转换解码数据并将其添加到现有数组:
function readCsvFile( csvFile) {
return new Promise( (resolve, reject) => {
fs.readFile(csvFile, 'UTF-8',
(err, csv) => err ? reject(err) : resolve( csv)
);
});
}
function decodeCsv( csv) {
return new Promise( (resolve, reject) => {
$.csv.toArrays(csv, {},
(err, data) => err ? reject( err) : resolve( data)
);
});
}
function extractNames( data) {
return data.map( item => item[0].toString());
}
function addNames( placeName, csvFile) {
return readCsvFile( csvFile)
.then(decodeCsv)
.then(extractNames)
.then( // push new names to placeName and return placeName
names => names.reduce( (a,name) => {a.push(name);return a}, placeName)
);
}
不使用async / await的用法要求在数据可用或发生错误后,添加用于实现和拒绝的promise处理程序异步调用:
var placeName = ["a","b"];
var csvFile = 'test.csv';
addNames( placeName, csvFile)
.then( placeName => console.log(placeName)) // log updated places
.catch( err => console.log( err)); // or log the error.
await
如上所述,await
运算符只能在异步函数中使用。它等待完成的promise数据,以便可以在同一个函数内进一步处理。
async function example() {
var placeName = ["a","b"];
var csvFile = 'test.csv';
await addNames( placeName, csvFile);
// do something with placeName
return somethingElse;
}
通过调用example
为返回的承诺添加履行和拒绝处理程序尚未显示。
return await
......请注意,从异步函数返回的promise将解析通过调用该函数返回的promise。因此编码模式
return await operand
包含一个不必要的await
运算符。
在节点中使用async
函数仍然需要将使用错误/成功回调的操作转换为返回promise的请求(“promisifying”操作),但在语法上允许编写代码处理请求在await
操作之后立即写入。生成的代码在样式上与过程代码类似。例如:
function readCsvFile( csvFile) {
return new Promise( (resolve, reject) => {
fs.readFile(csvFile, 'UTF-8',
(err, csv) => err ? reject(err) : resolve( csv)
);
});
}
function decodeCsv( csv) {
return new Promise( (resolve, reject) => {
$.csv.toArrays(csv, {},
(err, data) => err ? reject( err) : resolve( data)
);
});
}
async function addNames( placeName, csvFile) {
let csv = await readCsvFile( csvFile);
let arrays = await decodeCsv( csv);
let names = arrays.map( item => item[0].toString());
placeName.push.apply( placeName, names);
return placeName;
}