【问题标题】:Problem with fs.writeFile in reduce with fetch使用 fetch 减少 fs.writeFile 的问题
【发布时间】:2020-01-17 15:40:35
【问题描述】:

我需要一些关于我正在编写的助手的帮助。出于某种原因,在 readFile 的异步中使用归约,当尝试将结果写入文件时,它不会前进到数组的下一项。但是,如果我使用 console.log,它就可以正常工作。

const neatCsv = require('neat-csv');
const fetch = require('node-fetch');
const fs = require('fs');

fs.readFile('./codes.csv', async (err, data) => {
    if (err) { throw err; }

    let baseUrl = 'https://hostname/orders?from=2019-10-21T00:00:00.001Z&to=2019-12-31T23:59:59.000Z&promo=';
    const starterPromise = Promise.resolve(null);
    const promos = await neatCsv(data);
    const logger = (item, result) => console.log(item, result);

    function write (item, result) {
        return new Promise((resolve, reject) => {
            fs.writeFile(`./output/${item.PROMO}.json`, JSON.stringify(result), (err) => {
                if (err) { throw err; }
                console.log(`Wrote file ${item.PROMO}`);
            });
        })
    }

    function asyncFetch(item) {
        console.log(`runTask <---------${item.PROMO}---------`);
        return fetch(`${baseUrl}${item.PROMO}`, { headers: { 'x-apikey': 'xyz' }})
            .then(res => (res.json())
            .then(json => json))
    }

    await promos.reduce(
        (p, item) => p.then(() => asyncFetch(item).then(result => write(item, result))),
        starterPromise
    )
});

csv 文件只是这样的基本布局..

PROMO
12345
56789
98765
...

我们的目标是遍历这些,进行 REST 调用以获取 json 结果并将其写入具有当前促销名称的文件,然后移动到下一个,进行新调用并将该调用保存到不同的文件及其各自的代码。

在reduce中,如果你调用logger而不是write,它工作正常。调用write,它只是一遍又一遍地进行相同的调用并覆盖到同一个文件,迫使我杀死它。请帮忙,我在这里失去理智......

【问题讨论】:

    标签: javascript node.js async-await fetch reduce


    【解决方案1】:

    您可能会更好地使用async 函数、fs 承诺 API 和一个简单的 while 循环来使用 CSV 项目。干编码,自然,因为我没有你的 CSV 或 API。

    (您最初的问题可能是由于您在write 函数中没有resolve/reject,但也不需要reduce hell……)

    const neatCsv = require("neat-csv");
    const fetch = require("node-fetch");
    const fsp = require("fs").promises;
    
    const logger = (item, result) => console.log(item, result);
    
    const baseUrl = "https://hostname/orders?from=2019-10-21T00:00:00.001Z&to=2019-12-31T23:59:59.000Z&promo=";
    
    async function asyncFetch(item) {
      console.log(`runTask <---------${item.PROMO}---------`);
      const res = await fetch(`${baseUrl}${item.PROMO}`, { headers: { "x-apikey": "xyz" } });
      const json = await res.json();
      return json;
    }
    
    async function write(item, result) {
      await fsp.writeFile(`./output/${item.PROMO}.json`, JSON.stringify(result));
      console.log(`Wrote file ${item.PROMO}`);
    }
    
    async function process() {
      const data = await fsp.readFile("./codes.csv");
      const promos = await neatCsv(data);
      while (promos.length) {
        const item = promos.shift();
        const result = await asyncFetch(item);
        await write(item, result);
      }
    }
    
    process().then(() => {
      console.log("done!");
    });
    

    使用模拟数据和 JSON 占位符服务的版本可以正常工作:

    const fetch = require("node-fetch");
    const fsp = require("fs").promises;
    
    const baseUrl = "https://jsonplaceholder.typicode.com/comments/";
    
    async function asyncFetch(item) {
      console.log(`runTask <---------${item.PROMO}---------`);
      const res = await fetch(`${baseUrl}${item.PROMO}`);
      return await res.json();
    }
    
    async function write(item, result) {
      const data = JSON.stringify(result);
      await fsp.writeFile(`./output/${item.PROMO}.json`, data);
      console.log(`Wrote file ${item.PROMO}: ${data}`);
    }
    
    async function getItemList() {
      return [
        {PROMO: '193'},
        {PROMO: '197'},
        {PROMO: '256'},
       ];
    }
    
    async function process() {
      const promos = await getItemList();
      while (promos.length) {
        const item = promos.shift();
        const result = await asyncFetch(item);
        await write(item, result);
      }
    }
    
    process().then(() => {
      console.log("done!");
    });
    

    【讨论】:

    • 不幸的是,这也是同样的事情。我认为现在这是一个竞赛条件。用我的 api 尝试你的代码,它做同样的事情。当我使用模拟服务 (jsonplaceholder.typicode.com/todos/1) 尝试它时,它可以工作。只需确保在提取中删除 ${item.PROMO} 和标头即可。为了安全起见,我不能完全分享 api 的详细信息,希望你能理解。不过这很有帮助。一件有趣的事情是它从未真正完成,它只是不断循环 promos 数组的长度。
    • 如果它适用于模拟,你确定你调用你的服务正确吗?
    • 100% 肯定..它写入第一个文件并且响应就在那里。也许是我的响应大小?
    • 我添加了另一个版本(使用硬编码的“CSV”)和模拟服务——我真的不知道该告诉你什么,它工作得很好。您在哪个平台上,哪个 Node 版本?
    • 谢谢。我目前在 v10.15.3 上。我发现了问题,我让 nodemon 运行以在保存时重新运行。 writeFile 正在触发保存,导致脚本重新加载......愚蠢。我的原始脚本实际上工作得很好。有趣的是它在某些 writeFile 场景中工作。无论如何,再次感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    • 2017-11-15
    • 1970-01-01
    • 2021-12-26
    • 2015-11-19
    • 1970-01-01
    • 2021-04-22
    相关资源
    最近更新 更多