如何等待global.lastVideo非false/undefined时正确返回值
问题根因
首次调用返回undefined是典型的异步时序错误:client.request.parseURL是异步网络请求,返回Promise对象,JS执行到这里不会阻塞等待请求完成,会直接往下执行console.log和return逻辑。第一次调用时请求还没拿到返回值,global.lastVideo还没被赋值,自然输出undefined;第二次调用时第一次的请求刚好执行完成给全局变量赋了值,才会拿到正确结果。
靠全局变量存储异步结果本身存在竞态隐患,比如多个频道同时发起调用时值会互相覆盖,非常不推荐这种写法。
最优修复方案
直接把函数改成异步写法,等待请求完成后直接返回结果,彻底抛弃全局变量存值的逻辑:
async function getLastVideo(channel_id){ const resp = await client.request.parseURL(`https://www.youtube.com/feeds/videos.xml?channel_id=${channel_id}`); const lastVideo = resp.items[0].link; console.log('lastVideo: ' + lastVideo); return lastVideo; }
调用时需要用await或者.then接收结果,因为异步函数永远返回Promise:
// 用法1:在async环境下用await拿值 async function run() { const videoLink = await getLastVideo('目标频道ID'); // 后续需要用到videoLink的逻辑全部写在这里 } // 用法2:用.then接收返回值 getLastVideo('目标频道ID').then(videoLink => { // 拿到链接后的逻辑写在这里 });
备选方案(不推荐,仅兼容旧逻辑使用)
如果现有代码强依赖global.lastVideo全局变量,必须等这个变量有值再返回,可以写轮询检测逻辑,但这种写法性能差、需要额外处理请求失败/超时场景,容易出bug:
function getLastVideo(channel_id){ // 先发起请求 client.request.parseURL(`https://www.youtube.com/feeds/videos.xml?channel_id=${channel_id}`) .then(data => { global.lastVideo = data.items[0].link; }); // 轮询等待全局变量赋值 return new Promise((resolve, reject) => { let checkCount = 0; const timer = setInterval(() => { checkCount++; // 超时10秒直接抛错,避免死循环 if (checkCount > 200) { clearInterval(timer); reject(new Error('请求超时')); return; } if (global.lastVideo) { clearInterval(timer); console.log('lastVideo: ' + global.lastVideo); resolve(global.lastVideo); } }, 50); }); }
这个方案同样需要用await/.then接收结果,没有特殊兼容需求直接用第一种方案即可。
内容的提问来源于stack exchange,提问作者HattN
相关产品推荐
相关产品推荐

