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

NodeJS中无法在主程序用Await的问题及模块、顶层概念解惑

Node.js中使用await的语法错误与程序挂起问题解决

问题背景

我想在NodeJS主程序里使用await关键字,确保程序结束前获取到异步操作结果,同时避免程序挂起。尝试了直接用await、用async()包裹、不使用await等方案均未成功:

  • 初始代码运行触发错误:SyntaxError: await is only valid in async functions and the top level bodies of modules,产生两个疑问:是否不在模块中?是否不在顶层代码中?
  • 拆分主程序与模块、尝试立即执行异步函数表达式(IIFE)后,虽能获取Redis返回值,但程序始终挂起,需手动终止。

需要解决:修复await语法错误、明确module和top level概念、解决程序挂起问题。

相关代码

初始代码

const redis = require('ioredis');
const REDIS_RELATIX_HOST = "redis-xxxx.c277.us-east-1-3.ec2.cloud.redislabs.com"
const REDIS_RELATIX_PORT =  "12269"
const REDIS_RELATIX_PASSWORD = "mypassword"

let result = "dummy";       
const redisClient = redis.createClient({
            host: REDIS_RELATIX_HOST,
            port: REDIS_RELATIX_PORT,
            password: REDIS_RELATIX_PASSWORD 
        }) 
redisClient.on('error', err => {
    console.log('Error ' + err);
    });
await getSpanishWordForRed(); 
Console.Write("result=" + result); 
     
async function getSpanishWordForRed(){
    console.log("getSpanishWordForRed:start")
    await redisClient.hget('spanish', 'red', 
                           (err, value) => {
        if (err) console.log(err);
        else {
             console.log(value);
             result = value.toString(); 
             }
    });
    console.log("getSpanishWordForRed:end")
}

console.log("The end")

拆分后的主程序

var mySpanishWord = require('./redisTestNodeOnly8Module.js') 
console.log("main before await result"); 
result = mySpanishWord();
console.log("main result=" + result); 

模块文件redisTestNodeOnly8Module.js

exports.SpanishWordForRed = async function() {
    const redis = require('ioredis');
    const REDIS_RELATIX_HOST = "redis-xxxxx.c277.us-east-1-3.ec2.cloud.redislabs.com"
    const REDIS_RELATIX_PORT =  "12269"
    const REDIS_RELATIX_PASSWORD = "mypassword"

    const redisClient = redis.createClient({
                host: REDIS_RELATIX_HOST,
                port: REDIS_RELATIX_PORT,
                password: REDIS_RELATIX_PASSWORD 
            }) 
    redisClient.on('error', err => {
        console.log('Error ' + err);
        });
        
    let result = "dummy";       
    console.log("getSpanishWordForRed:start")
    await redisClient.hget('spanish', 'red', 
                           (err, value) => {
        if (err) console.log(err);
        else {
             console.log(value);
             result = value.toString(); 
             return value.toString(); 
             }
    });
}

问题解析与解决方案

1. 明确module与top level概念

  • Module(模块):Node.js中每个独立的.js文件都是一个模块,默认采用CommonJS规范(使用require/exports)。若想在顶层代码直接用await,需切换为ES模块:要么将文件后缀改为.mjs,要么在项目的package.json中添加"type": "module"。
  • Top Level(顶层代码):指模块文件中,不属于任何函数、代码块(如if、for)的代码区域。

2. 修复await语法错误

方案一:用IIFE包裹异步逻辑(适合CommonJS模块)

将需要使用await的代码放入立即执行的异步函数中,满足await只能在async函数内使用的规则:

(async () => {
  // 你的异步逻辑代码
})();

方案二:切换为ES模块

修改package.json添加"type": "module",之后即可在顶层直接使用await,同时需将require/exports替换为ES模块的import/export语法。

3. 解决程序挂起问题

程序挂起的核心原因是Redis客户端未关闭连接,Node.js会等待所有活跃的异步资源释放后才会退出。因此在获取结果后,需调用redisClient.quit()或redisClient.disconnect()关闭连接。

4. 代码中的其他问题修正

  • Node.js中控制台输出是console.log,而非Console.Write(注意大小写);
  • ioredis的hget若传入回调函数,返回的不是Promise,此时await不会生效,应使用Promise形式(去掉回调,直接await redisClient.hget(...))。

修正后的代码示例

修正后的初始代码(IIFE方案)

const redis = require('ioredis');
const REDIS_RELATIX_HOST = "redis-xxxx.c277.us-east-1-3.ec2.cloud.redislabs.com"
const REDIS_RELATIX_PORT =  "12269"
const REDIS_RELATIX_PASSWORD = "mypassword"

(async () => {
  let result = "dummy";       
  const redisClient = redis.createClient({
    host: REDIS_RELATIX_HOST,
    port: REDIS_RELATIX_PORT,
    password: REDIS_RELATIX_PASSWORD 
  });

  redisClient.on('error', err => {
    console.log('Error ' + err);
  });

  result = await getSpanishWordForRed(redisClient); 
  console.log("result=" + result); 
  console.log("The end");

  // 关闭Redis连接,避免程序挂起
  await redisClient.quit();
})();

async function getSpanishWordForRed(redisClient){
  console.log("getSpanishWordForRed:start")
  // 使用Promise形式的hget,去掉回调
  const value = await redisClient.hget('spanish', 'red');
  console.log(value);
  console.log("getSpanishWordForRed:end")
  return value.toString();
}

修正后的拆分模块版本

主程序

const { SpanishWordForRed } = require('./redisTestNodeOnly8Module.js');

(async () => {
  console.log("main before await result"); 
  const result = await SpanishWordForRed();
  console.log("main result=" + result); 
})();

模块文件redisTestNodeOnly8Module.js

const redis = require('ioredis');
const REDIS_RELATIX_HOST = "redis-xxxxx.c277.us-east-1-3.ec2.cloud.redislabs.com"
const REDIS_RELATIX_PORT =  "12269"
const REDIS_RELATIX_PASSWORD = "mypassword"

exports.SpanishWordForRed = async function() {
  const redisClient = redis.createClient({
    host: REDIS_RELATIX_HOST,
    port: REDIS_RELATIX_PORT,
    password: REDIS_RELATIX_PASSWORD 
  });

  redisClient.on('error', err => {
    console.log('Error ' + err);
  });
  
  console.log("getSpanishWordForRed:start")
  // 改用Promise形式调用hget
  const value = await redisClient.hget('spanish', 'red');
  console.log(value);
  // 关闭Redis连接
  await redisClient.quit();
  return value.toString();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 02:15:26