簡體   English   中英

解析大型 CSV 並流式傳輸承諾行

[英]Parsing large CSV and streaming rows of promises

在嘗試 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 和 csv 時有點混淆,為每一行發出 http 請求,並讓一切執行並以“正確”順序登錄到控制台。 最終,我認為我沒有正確地包裝我的承諾,或者......?

const getUserByEmail = async (email) => {
  const encodedEmail = encodeURIComponent(email);

  try {
    const response = await http.get(`users?email=${encodedEmail}`);
    const userId = response.data.data[0] && response.data.data[0].id;

    return (userId ? userId : `${email} not found`);
  } catch (error) {
    console.error('get user error: ', error);
  }
};

const run = async () => {
  console.log('==> Reading csv ...');

  const promises = [];
  const readStream = fs.createReadStream('import-test.csv')
    .pipe(csv.parse({ headers: true }))
    .on('error', (error) => console.error('stream error: ', error))
    .on('data', (row) => {
      promises.push(getUserByEmail(row.email));
    })
    .on('end', rowCount => {
      console.log(`==> Parsed ${rowCount} rows from csv ...`);
    })

  await Promise.all(promises)
    .then(values => console.log(values))

  console.log('==> End of script')
};

run();

我正在嘗試/期望上面的代碼獲取 csv 的每一行,將每個 http 調用(一個承諾)推送到一系列承諾,並按照我期望的順序執行/記錄到控制台。

這是我的實際 output:

==> Reading csv...
[]
==> End of script
==> Parsed 10 rows from csv ...

這就是我所期待的:

==> Reading csv...
==> Parsed 10 rows from csv ...
[
  QyDPkn3WZp,
  e75KzrqYxK,
  iqDXoEFMZy,
  PstouMRz3y,
  w188hLyeT6,
  g18oxMOy6l,
  8wjVJutFnh,
  fakeEmail@fakeDomain.com not found,
  QEHaG3cp7d,
  y8I4oX6aCe
]
==> End of script

對我來說最大的問題是在“==> 腳本結束”之后記錄了任何內容,這向我表明,我無法很好地掌握所有先前事件何時/為什么按它們的順序記錄。

最終——我還沒有到達那里——我還想將這些請求緩沖/計時到每分鍾 100 次,否則我將受到這個特定的 API 的速率限制。

謝謝!

孔 readStream 一直await Promise.all(promises)是同步的 - data事件是異步的並在另一個事件循環中填充承諾,因此當你調用 Promise.all 時承諾是一個空數組 - 你不是在等待 Promise.all - 你不是在等待 ZA5A3F0F287A4779AZ.all結束。 您可能希望將邏輯放在結束事件中,而不是像這樣

const run = async () => {
  console.log('==> Reading csv ...');

  const promises = [];
  const readStream = fs.createReadStream('import-test.csv')
    .pipe(csv.parse({ headers: true }))
    .on('error', (error) => console.error('stream error: ', error))
    .on('data', (row) => {
      promises.push(getUserByEmail(row.email));
    })
    .on('end', async rowCount => {
      await Promise.all(promises)
        .then(values => console.log(values))

      console.log('==> End of script')
    })
}

go 關於它的另一種更簡單的方法是使用異步迭代器 readStream 有一個可以使用的symbol.asyncIterator

const run = async () => {
  console.log('==> Reading csv ...');

  let rowCount = 0
  const promises = []
  const readStream = fs.createReadStream('import-test.csv')
    .pipe(csv.parse({ headers: true }))
  
  for await (let row of readStream) {
    rowCount++
    promises.push(getUserByEmail(row.email));
  }
    
  console.log(`==> Parsed ${rowCount} rows from csv ...`)

  await Promise.all(promises).then(console.log)

  console.log('==> End of script')
}

我會進一步限制並發性並執行以下操作:

const run = async () => {
  console.log('==> Reading csv ...');

  const result = []
  const readStream = fs.createReadStream('import-test.csv')
    .pipe(csv.parse({ headers: true }))
  
  for await (let row of readStream) {
    result.push(await getUserByEmail(row.email))
  }

  console.log(result)
  console.log('==> End of script')
}

如果您想提高異步迭代器的並發性,請查看這篇文章,但要小心。 使用此方法時結果可能出現故障

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM