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

在JavaScript/Node.js中同步获取YouTube视频标题失败求助

解决异步获取YouTube视频标题并更新DOM的问题

核心原因

你碰到的问题本质是JavaScript异步执行机制:异步操作(比如调用YouTube API获取标题)不会阻塞后续代码,所以你在异步回调外访问结果时,数据还没返回,自然是undefined。console.log在回调里能正常工作,是因为它要等数据返回后才会执行。


Node.js端解决方案

1. 把回调式API包装成Promise

多数老npm包用回调模式,我们可以自己包装成Promise,这样就能用async/await等待结果:

const getYoutubeTitle = require('get-youtube-title');

// 包装成Promise版本
function getYTTitle(videoId, apiKey) {
  return new Promise((resolve, reject) => {
    getYoutubeTitle(videoId, apiKey, (err, title) => {
      if (err) reject(err);
      else resolve(title);
    });
  });
}

// 异步函数中使用await
async function fetchVideoTitles(videoIds, apiKey) {
  const titles = [];
  // 逐个获取标题
  for (const id of videoIds) {
    try {
      const title = await getYTTitle(id, apiKey);
      titles.push(title);
      // 这里可以实时处理标题,比如通过socket.io推给客户端
    } catch (err) {
      console.error(`获取ID ${id} 标题失败:`, err);
      titles.push('未知标题');
    }
  }
  return titles;
}

// 使用示例
const videoIds = ['视频ID1', '视频ID2'];
const apiKey = '你的API密钥';
fetchVideoTitles(videoIds, apiKey).then(allTitles => {
  console.log(allTitles); // 所有标题获取完成后输出
  // 这里可将标题列表发送给客户端或存储
});

2. 并行获取多个标题(效率更高)

如果视频ID较多,用Promise.all并行请求比逐个等待更快:

async function fetchVideoTitlesParallel(videoIds, apiKey) {
  const titlePromises = videoIds.map(id => getYTTitle(id, apiKey));
  try {
    const allTitles = await Promise.all(titlePromises);
    return allTitles;
  } catch (err) {
    console.error('批量获取标题失败:', err);
    return [];
  }
}

客户端(jQuery/原生JS)解决方案

客户端同样要处理异步,所有依赖异步数据的DOM操作必须等数据返回后执行:

1. 原生JS + Fetch API

// 注意:前端直接用API密钥有泄露风险,建议优先通过服务器代理请求
async function getVideoTitleClient(videoId, apiKey) {
  try {
    const response = await fetch(`https://www.googleapis.com/youtube/v3/videos?id=${videoId}&key=${apiKey}&part=snippet`);
    const data = await response.json();
    return data.items[0].snippet.title;
  } catch (err) {
    console.error('获取标题失败:', err);
    return '未知标题';
  }
}

// 更新播放列表DOM
async function updatePlaylist(videoIds, apiKey) {
  const playlistDiv = document.getElementById('playlist');
  playlistDiv.innerHTML = ''; // 清空原有内容

  for (const id of videoIds) {
    const title = await getVideoTitleClient(id, apiKey);
    const item = document.createElement('div');
    item.innerText = title;
    playlistDiv.appendChild(item);
  }
}

// 调用示例
updatePlaylist(['视频ID1', '视频ID2'], '你的API密钥');

2. jQuery版本

function getVideoTitleJquery(videoId, apiKey) {
  return new Promise((resolve, reject) => {
    $.get(`https://www.googleapis.com/youtube/v3/videos`, {
      id: videoId,
      key: apiKey,
      part: 'snippet'
    })
    .done(data => {
      resolve(data.items[0].snippet.title);
    })
    .fail(err => {
      reject(err);
    });
  });
}

async function updatePlaylistJquery(videoIds, apiKey) {
  const $playlist = $('#playlist');
  $playlist.empty();

  for (const id of videoIds) {
    try {
      const title = await getVideoTitleJquery(id, apiKey);
      $playlist.append(`<div>${title}</div>`);
    } catch (err) {
      $playlist.append(`<div>未知标题</div>`);
    }
  }
}

// 调用示例
updatePlaylistJquery(['视频ID1', '视频ID2'], '你的API密钥');

关键注意点

  • 所有依赖异步数据的操作(更新DOM、使用数组结果)必须放在回调、.then()或者await之后,不能在异步操作外部直接访问结果。
  • 前端直接暴露API密钥存在被恶意爬取的风险,建议优先通过Node.js服务器代理API请求,客户端从服务器获取标题。
  • 必须添加错误处理(try/catch或.catch()),避免API请求失败导致程序崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 07:25:18