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

使用Node.js时返回含模板字符串的变量为何得到undefined?

问题原因与解决方案

核心问题

langs函数返回undefined的根本原因是异步操作的回调返回无效:

  • fs.readdir是异步IO函数,你在它的回调里return html_languages,这个return只属于回调函数本身,和外层的langs函数无关。
  • langs函数没有任何顶层的return语句,所以调用时自然返回undefined。
  • 额外问题:fs.readFile无法读取目录,当getId为null时,你传入data/会触发错误。

解决方案

方案1:使用回调函数处理异步结果

修改langs函数,通过回调传递结果:

function langs(path_data, callback) {
  let html_languages = `<ul>`;
  fs.readdir(path_data, function(err, list_file) {
    // 处理异步错误
    if (err) {
      callback(err);
      return;
    }
    for(let i = 0; i < list_file.length; i++){
      let fileName = list_file[i].split('.')[0];
      html_languages += `<li><a href="/?id=${fileName}">${fileName}</a></li>`;
    }
    html_languages += `</ul>`;
    // 传递处理后的HTML
    callback(null, html_languages);
  });
}

然后修改HTTP服务中的调用逻辑,等待回调结果:

var app = http.createServer(function(request,response){
  var queryData = new URL('http://localhost:3000' + request.url)

  if(queryData.pathname === '/'){
    let getId = queryData.searchParams.get('id')
    let file_name;
    let title;
    let path_data = './data'

    // 调用langs并等待结果
    langs(path_data, function(err, html_languages) {
      // 错误时显示默认内容
      if (err) {
        html_languages = '<ul><li>目录加载失败</li></ul>';
      }

      // 修正目录读取问题:指向具体文件而非目录
      if(getId === null){
        file_name = 'data/index.html'; // 创建对应的欢迎页文件
        title = 'Welcome';
      } else {
        title = getId;
        file_name = 'data/' + title + '.html';
      }

      fs.readFile(file_name, 'utf8', function(err, description){
        let desc = description || 'Hello, nodeJs.';

        let template = `
        <!doctype html>
          <html>
          <head>
            <title>WEB1 - ${title}</title>
            <meta charset="utf-8">
          </head>
          <body>
            <h1><a href="/">WEB</a></h1>
            ${html_languages}
            <h2>${title}</h2>
            <p>${desc}</p>
          </body>
        </html>
        `
        response.writeHead(200);
        response.end(template);
      })
    })
  } else {
    response.writeHead(404);
    response.end();
  }
}); 
app.listen(3000);

方案2:使用Promise + Async/Await(更现代的写法)

利用Promise封装异步操作,结合async/await让代码更简洁:

// 用Promise封装langs函数
function langs(path_data) {
  return new Promise((resolve, reject) => {
    let html_languages = `<ul>`;
    fs.readdir(path_data, function(err, list_file) {
      if (err) {
        reject(err);
        return;
      }
      for(let i = 0; i < list_file.length; i++){
        let fileName = list_file[i].split('.')[0];
        html_languages += `<li><a href="/?id=${fileName}">${fileName}</a></li>`;
      }
      html_languages += `</ul>`;
      resolve(html_languages);
    });
  });
}

修改HTTP服务为async函数,用await等待结果:

var app = http.createServer(async function(request,response){
  var queryData = new URL('http://localhost:3000' + request.url)

  if(queryData.pathname === '/'){
    let getId = queryData.searchParams.get('id')
    let file_name;
    let title;
    let path_data = './data'
    let html_languages;

    try {
      // 等待langs的异步结果
      html_languages = await langs(path_data);
    } catch(err) {
      html_languages = '<ul><li>目录加载失败</li></ul>';
    }

    if(getId === null){
      file_name = 'data/index.html';
      title = 'Welcome';
    } else {
      title = getId;
      file_name = 'data/' + title + '.html';
    }

    fs.readFile(file_name, 'utf8', function(err, description){
      let desc = description || 'Hello, nodeJs.';
      let template = `
      <!doctype html>
        <html>
        <head>
          <title>WEB1 - ${title}</title>
          <meta charset="utf-8">
        </head>
        <body>
          <h1><a href="/">WEB</a></h1>
          ${html_languages}
          <h2>${title}</h2>
          <p>${desc}</p>
        </body>
      </html>
      `
      response.writeHead(200);
      response.end(template);
    })
  } else {
    response.writeHead(404);
    response.end();
  }
}); 
app.listen(3000);

方案3:使用Node.js内置的Promise版fs(最简洁)

Node.js提供了fs.promises模块,直接返回Promise,无需手动封装:

async function langs(path_data) {
  let html_languages = `<ul>`;
  // 直接用await读取目录
  const list_file = await fs.promises.readdir(path_data);
  for(const file of list_file){
    let fileName = file.split('.')[0];
    html_languages += `<li><a href="/?id=${fileName}">${fileName}</a></li>`;
  }
  html_languages += `</ul>`;
  return html_languages;
}

HTTP服务的调用逻辑和方案2一致,用async/await即可。

注意事项

  • 始终处理异步操作的错误,避免服务因未捕获的异常崩溃。
  • fs.readFile只能读取文件,若要处理目录,需用fs.readdir或fs.stat判断类型。
  • 字符串拼接可以用+=简化,或者用数组push后join,性能更优(文件数量多时更明显)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 19:12:20