虽然我在概念上理解节点(和ajax&#s; s)异步行为,但我总是对我认为必须是常规任务感到困惑。请考虑以下伪代码:
let result = [];
request("http://server", function(error, response) {
const links = response.links; // an array of links
links.forEach(function(link) {
request(link, function(error, response) {
result.push(response.gold);
});
// *****C*****
});
// *****B*****
});
// *****A*****
我的问题是,何时将结果返回到网络以便返回完整的结果?在A
和B
,结果可能尚未准备就绪,但如果我以某种流式方式执行此操作,我只能从C
返回结果,我不会这样做。我知道怎么做。处理这样的事情的正确方法是什么(并且,假设我在第一个response
中只显示了一个下降级别,我将如何处理任意数量的级别)?另外,我想知道在不使用任何外部帮助程序库(如async
)的情况下执行此操作的方法。我没有反对使用类似的东西,但我想了解在nodejs
中应该如何处理它的异步性质。
答案 0 :(得分:0)
您可以使用promisses以及nodejs v8中的async
和await
对此进行归档。
首先,您需要让您的请求函数返回一个promise,而不是使用回调。所以要么宣传它,要么使用返回承诺的库。 现在你可以像这样编写一个异步函数
var requestPromisified = require('request-promise');
async function getGoldData() {
var response = await requestPromisified('http://example.com');
var links = ['http://example.com']; //get links somehow from response
var goldPromises = links.map(async function (link) {
var response = await requestPromisified(link);
var gold = 0; //get gold somehow from response
return gold;
});
return Promise.all(goldPromises);
}
然后在其他异步上下文中使用该函数,例如在快速路由回调中。 (其他建议:使用模块express-promise-router,这样您就不必使用next(err);
此模块会自动将被拒绝的承诺传递给下一个中间件。)
var router = require('express-promise-router')();
router.get('/', async function(req, res) {
var goldData = await getGoldData();
console.log(goldData);
res.json(goldData);
});
或者在任何地方调用它:
getGoldData().then(function(goldData){
console.log('goldData:', goldData);
}).catch(function(err){
console.log('ERROR:', err);
});
答案 1 :(得分:0)
让我们尝试解析两个youtube网址并让它们处理。承诺会使代码更容易推理。
const sonyPictures = 'https://www.youtube.com/playlist?list=PLYeOyMz9C9kYmnPHfw5-ItOxYBiMG4amq';
const fox = 'https://www.youtube.com/playlist?list=PLfPBohF1uFwoO5wBnYD67i0pbZ6GqrGEd';
const allURLs = [sonyPictures, fox];
所以现在我们有一个我们想要循环的数组。现在我们需要发出请求并保存承诺
const cheerio = require('cheerio');
const rp = require('request-promise');
const playlistArrayPromises = [];
...
allURLs.forEach((channelURL) => {
const options = {
uri: channelURL,
transform: function (body) {
return cheerio.load(body);
},
};
playlistArrayPromises.push(rp(options));
下一步是等待所有这些承诺解决(或拒绝),我们可以执行我们想要的行动
Promise.all(playlistArrayPromises).then((result) => {
console.log(result.length);
console.log('here');
return 0;
});
现在,结果按照请求的顺序包含了所有parsedURL响应。
您可以将此扩展到您想要的任何级别。您所要做的就是等待所有承诺通过Promise.all在子级别解决,一旦完成,您可以继续进行。
以下是您可以使用node和所需的软件包运行的完整代码。
const cheerio = require('cheerio');
const rp = require('request-promise');
const sonyPictures = 'https://www.youtube.com/playlist?list=PLYeOyMz9C9kYmnPHfw5-ItOxYBiMG4amq';
const fox = 'https://www.youtube.com/playlist?list=PLfPBohF1uFwoO5wBnYD67i0pbZ6GqrGEd';
const allURLs = [sonyPictures, fox];
const playlistArrayPromises = [];
const main = () => {
allURLs.forEach((channelURL) => {
const options = {
uri: channelURL,
transform: function (body) {
return cheerio.load(body);
},
};
playlistArrayPromises.push(rp(options));
});
Promise.all(playlistArrayPromises).then((result) => {
console.log(result.length);
return 0;
});
};
main();
答案 2 :(得分:-1)
你已经使用了函数push,它基本上添加了LIFO形式的元素。而不是使用,取消移位功能。 所以,如果你不理解https://www.w3schools.com/jsref/jsref_unshift.asp 看到这个链接。