Node.js循环中Promise使用异常求助:Twitter推文翻译流程问题
问题分析与解决方案
我一眼就看出你遇到的问题啦——Promise.all()的执行时机完全错了!
问题根源
T.get()是Twitter提供的异步API调用,它的回调函数要等API返回数据后才会执行。但你把Promise.all(promises)写在了T.get()的外面,这就导致:在Twitter请求还没拿到数据、promises数组还是空数组的时候,Promise.all就已经运行了。空数组的Promise.all会立刻resolve,所以你会看到"ALL PROMISES DONE"直接打印出来,完全没等翻译任务开始。
解决方案1:调整Promise.all的位置
最简单的修复方式是把Promise.all移到T.get()的回调函数内部,确保只有在promises数组被填充完翻译任务后,才去等待所有Promise完成:
var Twit = require('twit') var T = new Twit({ consumer_key: '...', consumer_secret: '...', access_token: '...', access_token_secret: '...', timeout_ms: 60*1000, // optional HTTP request timeout to apply to all requests. }) //TWITTER app.post('/twitter/search/hashtags', function (req, res) { // TWITTER QUERY PARAMS var params = { q: req.body.search, count: 2, //lang: 'fr' } //GData var bloc = []; var promises = []; // TWITTER API GET INFORMATION T.get('search/tweets', params, function(err, data, response) { // if there no errors if (!err) { //PROCESSING DATA FROM TWITTER if(data){ for(var i= 0; i < data.statuses.length; i++){ //translate all text string which are not in french var lang = data.statuses[i].lang; var str = data.statuses[i].text; if(lang != "fr"){ promises.push(translate_str(data.statuses[i].user.screen_name, str, lang)); } } } // 把Promise.all移到这里!确保promises数组已经填充完毕 Promise.all(promises) .then(function(translatedData){ console.log("ALL PROMISES DONE"); console.log(translatedData); // 在这里把结果返回给前端 res.send(translatedData); }) .catch(function(err){ console.error(err); res.status(500).send('Translation failed'); }); } // if unable to Search a tweet else { console.log('Something went wrong while SEARCHING...'); console.log(err); res.status(500).send('Twitter search failed'); } }); //TRANSLATE - 优化:去掉不必要的Promise嵌套 function translate_str(name, str, lang){ return translate(str, {from: lang, to: 'fr'}) .then(res => { console.log('TRANSLATED INTO :'); console.log(res.text); //SENTIMENT ANALYSIS var r1 = sentiment(res.text, 'fr'); console.log(r1.score); console.log(r1.positive); //IF SCORE POSITIVE THEN PUSH TO FRONT if(r1.score > 0){ return { name: name, text: res.text, lang: lang, selected: false }; } // 分数非正的情况可以返回null,后续可以过滤掉 return null; }) .catch(err => { console.error(err); throw err; // 抛出错误让Promise.all捕获 }); } })
解决方案2:用Promise包装+async/await让代码更整洁
如果想避免回调嵌套,让代码逻辑更清晰,可以把T.get()包装成Promise,然后用async/await来编写异步逻辑:
var Twit = require('twit') var T = new Twit({ consumer_key: '...', consumer_secret: '...', access_token: '...', access_token_secret: '...', timeout_ms: 60*1000, // optional HTTP request timeout to apply to all requests. }) // 把T.get包装成Promise函数 function fetchTwitterTweets(params) { return new Promise((resolve, reject) => { T.get('search/tweets', params, (err, data) => { if (err) reject(err); else resolve(data); }); }); } //TWITTER app.post('/twitter/search/hashtags', async function (req, res) { try { // TWITTER QUERY PARAMS const params = { q: req.body.search, count: 2, //lang: 'fr' }; // 等待Twitter API返回数据 const data = await fetchTwitterTweets(params); const promises = []; if(data){ for(let i= 0; i < data.statuses.length; i++){ const lang = data.statuses[i].lang; const str = data.statuses[i].text; if(lang != "fr"){ promises.push(translate_str(data.statuses[i].user.screen_name, str, lang)); } } } // 等待所有翻译任务完成 const translatedData = await Promise.all(promises); console.log("ALL PROMISES DONE"); console.log(translatedData); // 返回过滤掉非正分数的结果给前端 res.send(translatedData.filter(item => item !== null)); } catch(err) { console.error('Error occurred:', err); res.status(500).send('Operation failed'); } }); //TRANSLATE - 优化后的函数 function translate_str(name, str, lang){ return translate(str, {from: lang, to: 'fr'}) .then(res => { console.log('TRANSLATED INTO :'); console.log(res.text); const r1 = sentiment(res.text, 'fr'); console.log(r1.score); console.log(r1.positive); return r1.score > 0 ? { name, text: res.text, lang, selected: false } : null; }) .catch(err => { console.error(err); throw err; }); }
额外优化点
- 你的
translate_str函数原本手动包了一层Promise,其实完全没必要——因为translate()已经返回Promise了,直接return它的链式调用即可,这样代码更简洁。 - 可以在最后过滤掉
translate_str返回的null值(也就是分数非正的推文),只把符合条件的数据返回给前端。
内容的提问来源于stack exchange,提问作者SKYnine
相关产品推荐
相关产品推荐

