Неожиданное поведение при использовании модуля узла csv-parser
Я пытаюсь получить заголовки файла csv в массив и пытаюсь использовать csv-parser для этого. Две вещи, которые я не могу понять здесь:
1) Почему console.log в последней строке кода запускается раньше всего? Это также означает, что значение переменной, которую я пытаюсь записать, не определено.
2) Почему моя функция getFields не возвращает недавно заполненный массив заголовков? Я могу console.log массив результатов со всеми его новыми элементами изнутри функции, но на самом деле я не могу вернуть массив, полный элементов - он продолжает возвращать пустой массив.
Вот код:
const express = require('express')
const app = express()
const port = 3000
const csv = require('csv-parser')
const fs = require('fs')
function getFields (filePath) {
let results = [];
fs.createReadStream(filePath)
.pipe(csv())
.on('headers', (headers) => {
let values = Object.values(headers);
values.forEach(function(element) {
results.push(element);
});
console.log('I am actually getting results here: ', results);
return results;
});
}
const omg = getFields(thisIsAFilePath)
console.log('This console.log is firing before anything else: ', omg)
1 ответ
Ваш код использует асинхронный обратный вызов. Это означает, что обработчик события ((headers) => {...}
функция) выполняется, когда происходит событие (в данном случае headers
) уволен. Это происходит асинхронно, пока продолжается оставшийся сценарий.
Это означает, что происходит следующее:
- Функция объявлена
- Функция вызывается, так как ничего не возвращает (даже не имеет
return
заявление),undefined
хранится внутриomg
console.log
вызов выполнен- В какой-то момент в будущем событие
headers
запущен и выполнит функцию(headers) => { ... }
Поэтому, если вам нужны результаты, вам нужно поместить код в функцию обратного вызова или вызвать функцию изнутри следующим образом:
function handleHeaders(headers) {
console.log(headers);
}
function getFields (filePath) {
let results = [];
fs.createReadStream(filePath)
.pipe(csv())
.on('headers', (headers) => {
handleHeaders(headers);
});
}
Альтернатива: обещание
В качестве альтернативы вы можете использовать API Promise, который позволит писать ваш код следующим образом:
(async () => {
function getFields(filePath) {
return new Promise(resolve => {
let results = [];
fs.createReadStream(filePath)
.pipe(csv())
.on('headers', (headers) => {
let values = Object.values(headers);
values.forEach(function (element) {
results.push(element);
});
console.log('I am actually getting results here: ', results);
resolve(results);
});
});
}
const omg = await getFields(thisIsAFilePath)
console.log('This console.log is firing before anything else: ', omg)
})();
Имейте в виду, что код также выполняется асинхронно, он просто скрыт в форме обещаний.