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

Node.js中如何同步不同模块中无返回值的函数?

问题:Node.js批量处理数据时因异步操作导致超时

我是Node.js新手,首次提问,表述不当请见谅。main.js处理小范围数据正常,但处理大范围数据时会超时,原因是数据获取与插入操作不同步。流程如下:

  • main.js通过for循环调用fetchPincode.js中的fetchPincode函数
  • 该函数使用https.get从指定URL提取数据
  • 提取的数据通过insertMany.js中的insertMany函数批量插入MongoDB

我希望insertMany能等待https.get完成后再执行,实现同步但未能成功,相关代码如下:

main.js

const fetchPincode = require('./fetchPincode.js')

const start_pincode = 110001
const end_pincode = 110097
for(let i=start_pincode;i<=end_pincode;i++) {
    // console.log('state.js '+i)
    fetchPincode.fetchPincode(i)
}

fetchPincode.js

require('dotenv').config()
const https = require('https')
const insertMany = require('./insertMany.js')
function fetchPincode(pincode) {
    https.get(process.env.PINCODE_URL+pincode,(res)=>{
        let data = ''
        res.on('data',(d)=>{
            data += [d]
            if (JSON.parse(data)[0].PostOffice != null) {
                insertMany.insertMany(JSON.parse(data)[0].PostOffice,pincode)
                // console.log(JSON.parse(data)[0].PostOffice)
            }
        })
    })
}

module.exports = {fetchPincode}

insertMany.js

const MongoClient = require('mongodb').MongoClient
function insertMany(data,pincode) {
    console.log(data)
    MongoClient.connect(process.env.MO_POSTAL,(error,db)=>{
        if (error) throw error
        // console.log('==========> MongoDB Connected')
        db.db('POSTAL').collection('POSTOFFICE').insertMany(data,(error,res)=>{
            if (error) throw error
            console.log(`For pincode: ${pincode}, ${res.insertedCount} rows inserted`)
            db.close()
        })
    })
}

module.exports = {insertMany}

.env

PINCODE_URL='https://api.postalpincode.in/pincode/'
MO_POSTAL='mongodb+srv://abcd:abcd@cluster0.abcd.mongodb.net/POSTAL?keepAlive=true&socketTimeoutMS=2100000000&connectTimeoutMS=2100000000&serverSelectionTimeoutMS=2100000000'
解决方案

问题根源

  1. https.get的数据接收是分段的,你在data事件中直接解析完整JSON,可能数据还没接收完就触发解析,导致错误或不完整操作
  2. 循环中一次性发起所有请求,并发过高,超出API或MongoDB的处理能力,引发超时
  3. 所有异步操作未通过Promise/async-await控制顺序,无法保证insertMany在数据获取完成后执行

修改后的代码

1. fetchPincode.js(Promise化+等待数据接收完成)

require('dotenv').config()
const https = require('https')
const insertMany = require('./insertMany.js')

function fetchPincode(pincode) {
  return new Promise((resolve, reject) => {
    https.get(process.env.PINCODE_URL + pincode, (res) => {
      let data = ''
      // 分段接收数据,累加即可
      res.on('data', (d) => {
        data += d
      })
      // 数据接收完成后再处理
      res.on('end', () => {
        try {
          const result = JSON.parse(data)[0]
          if (result.PostOffice) {
            // 等待插入操作完成再标记当前请求处理完毕
            return insertMany.insertMany(result.PostOffice, pincode)
              .then(resolve)
              .catch(reject)
          }
          resolve()
        } catch (err) {
          reject(new Error(`解析${pincode}数据失败:${err.message}`))
        }
      })
      // 监听请求错误
      res.on('error', (err) => reject(new Error(`获取${pincode}数据失败:${err.message}`)))
    }).on('error', (err) => reject(new Error(`发起${pincode}请求失败:${err.message}`)))
  })
}

module.exports = { fetchPincode }

2. insertMany.js(Promise化操作)

const MongoClient = require('mongodb').MongoClient

function insertMany(data, pincode) {
  return new Promise((resolve, reject) => {
    MongoClient.connect(process.env.MO_POSTAL, (error, client) => {
      if (error) {
        return reject(new Error(`连接MongoDB失败:${error.message}`))
      }
      client.db('POSTAL').collection('POSTOFFICE').insertMany(data, (error, res) => {
        // 无论成功失败都关闭连接
        client.close()
        if (error) {
          return reject(new Error(`插入${pincode}数据失败:${error.message}`))
        }
        console.log(`For pincode: ${pincode}, ${res.insertedCount} rows inserted`)
        resolve(res)
      })
    })
  })
}

module.exports = { insertMany }

3. main.js(串行控制并发)

const fetchPincode = require('./fetchPincode.js')

const start_pincode = 110001
const end_pincode = 110097

// 用async-await实现串行处理,避免并发过高
async function processPincodes() {
  for (let i = start_pincode; i <= end_pincode; i++) {
    try {
      await fetchPincode.fetchPincode(i)
      console.log(`✅ 处理完成:${i}`)
    } catch (err) {
      console.error(`❌ 处理${i}失败:`, err.message)
      // 可选:遇到错误是否继续处理后续邮编,这里选择继续
      continue
    }
  }
  console.log('所有邮编处理完成')
}

processPincodes()

额外优化建议

  • 如果需要更高效率,可以用并发控制库(如p-limit)限制同时处理的请求数(比如一次处理5个),避免串行太慢
  • 可以复用MongoDB连接,不用每次插入都重新连接,提升性能
  • 给API请求添加超时时间,避免长时间无响应

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:15:31