You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js循环中按顺序执行REST API调用函数的问题求助

问题分析与修复方案

核心问题点

你的代码出现执行顺序混乱、数据丢失的问题,根源在于以下几个异步编程的常见错误:

  1. var声明导致的变量作用域泄漏:循环中用var obj,变量会被提升到main函数作用域,所有异步函数最终引用的都是循环最后一次的obj值。
  2. 异步函数未正确返回Promise:createDocument内部的fetch是异步操作,但函数直接return,没有等待请求完成,await createDocument()无法起到等待效果。
  3. 未等待异步函数完成就进入下一次循环:循环中直接调用updatePublication(),没有加await,导致所有迭代的API请求并行触发,完全打乱执行顺序。
  4. 共享变量id引发竞态条件:多个异步操作同时修改全局的id,后续的updatePublication拿到的不是对应createDocument返回的ID。
  5. 缺乏错误处理:fetch请求失败时没有捕获异常,无法排查请求失败的原因。

修复后的完整代码

const csv = require("csvtojson");
const jq = require('node-jq');

const parentFolder = 1234;
const token = "";
const csvFilePath = 'licenses.tsv';
const parentPublicationId = 5678;

// 封装createDocument为返回Promise的函数,直接返回创建的文档ID
async function createDocument(name) {
  const content = `<title>${name}</title></section>`;
  const inputBody = {
    "parent": parentFolder,
    "name": name,
    "content": content,
    "subtype": "component"
  };
  const headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Basic ' + token,
  };

  const res = await fetch('https://thesite.com/api/v2/documents', {
    method: 'POST',
    body: JSON.stringify(inputBody),
    headers: headers
  });

  if (!res.ok) {
    throw new Error(`创建文档失败:${res.status} ${res.statusText}`);
  }

  const body = await res.json();
  console.log('创建文档响应:', body);
  return body.id;
}

// 封装updatePublication,接收文档ID作为参数,避免共享变量
async function updatePublication(documentId) {
  const inputBody = {
    "parent": parentPublicationId,
    "document": documentId,
    "position": null, // 这里应该用null而不是字符串"null"
  };
  const headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Basic ' + token,
  };

  const res = await fetch('https://thesite.com/api/v2/forks', {
    method: 'POST',
    headers: headers,
    body: JSON.stringify(inputBody)
  });

  if (!res.ok) {
    throw new Error(`更新出版物失败:${res.status} ${res.statusText}`);
  }

  const body = await res.json();
  console.log('更新出版物响应:', body);
}

async function main() {
  try {
    // 简化TSV转JSON的流程,直接用await接收结果
    const jsonObj = await csv({ delimiter: '\t' }).fromFile(csvFilePath);
    
    // 简化jq处理流程,直接接收结果并解析
    const jsonOutput = await jq.run('[.[] | {name: .sourceName}]', jsonObj, { input: 'json' });
    const parsed = JSON.parse(jsonOutput);

    // 用for...of循环确保每次迭代的变量独立,且顺序执行
    for (const item of parsed) {
      console.log(`开始处理:${item.name}`);
      const docId = await createDocument(item.name);
      await updatePublication(docId);
      console.log(`完成处理:${item.name}`);
    }

    console.log('所有任务执行完成');
  } catch (err) {
    console.error('执行出错:', err);
    process.exit(1);
  }
}

main();

关键修改说明

  1. 提取异步函数到外部:把createDocument和updatePublication从循环中提取出来,避免每次循环重新创建函数,同时让逻辑更清晰。
  2. 异步函数返回Promise并传递参数:createDocument直接返回创建成功的文档ID,updatePublication接收该ID作为参数,彻底避免共享变量的竞态问题。
  3. 使用for...of循环:替代for...in+var,确保每次迭代的变量item是独立的,不会被后续迭代覆盖。
  4. 循环中添加await:每次迭代都等待createDocument和updatePublication完成后再进入下一次,保证执行顺序严格按CSV行顺序进行。
  5. 完善错误处理:在fetch后检查响应状态,用try/catch包裹整个流程,方便排查错误。
  6. 简化TSV转JSON和jq处理:直接用await接收库的返回结果,去掉冗余的中间变量。

内容的提问来源于stack exchange,提问作者hcdocs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:40:53