在谈到文档之前,我已经和他们一点也没有帮助。
我有一个以节点为骨干的网页。在一个页面上,我需要从NASA的当日天文图片(APOD)API请求过去的10张图像,然后我需要从Launch Library API请求接下来的5次即将发布({{3} })。我的问题是并不是所有的APOD都会加载(我理解这是因为异步请求的性质)。
这是我对Node后端的简洁app.js文件:
app.get("/index", function(req, res) {
/**Requesting NASA's Astronomy Picture of the Day**/
var apod_url = "https://api.nasa.gov/planetary/apod?api_key=[My Key]"
var apod_img_urls = [];
var curr_moment = moment();
for(var i = 0; i < 10; i++) {
var appended_url = apod_url + "&date=" + curr_moment.subtract(i, "days").format("YYYY-MM-DD");
request(appended_url, function(error, reponse, body) {
if(!error && reponse.statusCode == 200) {
var img_json = JSON.parse(body);
if(img_json.media_type == "image") {
var apod_promise = new Promise(function(resolve, reject){
resolve(img_json.hdurl);
});
apod_img_urls.push(apod_promise);
}
} else {
console.log(error);
}
});
}
/**************************************************/
var url = "https://launchlibrary.net/1.3/launch?next=20&mode=verbose";
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
res.render("index", {data: data, apod_img_urls: apod_img_urls});
} else {
console.log(error);
}
});
});
这是一个EJS代码段
<% apod_img_urls.forEach(function(promise, index) { %>
<div class="carousel-item <%= (index == 0 ? 'active' : '') %>">
<div class="w-100 home-image" style="background-image: url('<%= promise.then(function(url) {return url}); %>')"></div>
</div>
<% }); %>
当我检查来源时,它显示div的背景图片网址是[object Promise]。我拥有它的方式,没有图像出现。显示的div的数量(即我应该拥有的图像的数量)也是可变的;有时它是5,有时它是3,有时则是3。我的问题可能是我在另一个请求中呈现页面吗?另外,如何才能将实际图像URL显示在EJS文件中?
答案 0 :(得分:2)
你正在创建承诺太迟了,在reequest的异步回调中 - 需要相当简单的代码重组
一旦所有承诺都在一个数组中,你需要等待它们完成,使用Promise.all
app.get("/index", function(req, res) {
/**Requesting NASA's Astronomy Picture of the Day**/
var apod_url = "https://api.nasa.gov/planetary/apod?api_key=[My Key]"
var promises = [];
var curr_moment = moment();
for(var i = 0; i < 10; i++) {
var appended_url = apod_url + "&date=" + curr_moment.subtract(i, "days").format("YYYY-MM-DD");
promises.push(new Promise((resolve, reject) => {
request(appended_url, function(error, reponse, body) {
if(!error && reponse.statusCode == 200) {
var img_json = JSON.parse(body);
resolve(img_json.hdurl);
} else {
reject(error);
console.log(error);
}
});
}));
}
Promise.all(promises).then(apod_img_urls => {
var url = "https://launchlibrary.net/1.3/launch?next=20&mode=verbose";
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
res.render("index", {data, apod_img_urls});
} else {
console.log(error);
}
});
});
});
除了使用请求承诺和它所需要的所有内容之外,您始终可以创建自己的有效request
函数,在这种情况下,如果状态不是200
const requestP = url => new Promise((resolve, reject) => request(url, (error, response, body) => {
if (error) {
reject({error, response, body});
} else if (resonse.statusCode != 200) {
reject(resonse.statusCode);
} else {
resolve({response, body});
}
}));
现在,您的代码可以写成:
app.get("/index", function(req, res) {
/**Requesting NASA's Astronomy Picture of the Day**/
const apod_url = "https://api.nasa.gov/planetary/apod?api_key=[My Key]"
const curr_moment = moment();
Promise.all(Array.from({length:10}, (_, i) => {
const appended_url = apod_url + "&date=" + curr_moment.subtract(i, "days").format("YYYY-MM-DD");
return requestP(appended_url).then(({response, body}) => JSON.parse(body).hdurl);
})).then(apod_img_urls => {
const url = "https://launchlibrary.net/1.3/launch?next=20&mode=verbose";
return requestP(url).then(({response, body}) => {
const data = JSON.parse(body);
return res.render("index", {data, apod_img_urls});
});
});
});
注意:那里有很多ES2015 +正在进行中
答案 1 :(得分:1)
如果您使用承诺返回请求库,如request-promise
,那么您可以执行以下操作:
app.get("/index", function(req, res) {
var apod_url = "https://api.nasa.gov/planetary/apod?api_key=[My Key]"
var curr_moment = moment();
var urls = [];
for(var i = 0; i < 10; i++) {
urls[i] = apod_url + "&date=" + curr_moment.subtract(i, "days").format("YYYY-MM-DD");
}
Promise.all(urls.map(url => rp({ url, json: true})).then((results) => {
// here you have all results with JSON already parsed for you
// ...
}).catch((err) => {
// handle error
// make sure to return response to client
// ...
});
// ...
});
如果您想使用promises,请使用承诺返回模块,例如request-promise
或axios
,而不是标准request
,请参阅:
或者,使用bluebird.promisify
或内置util.primisify
(自8.0开始)宣传request
模块,请参阅:
有关宣传request
的更多选项,请参阅:
然后,当你有一个promise-returns请求库时,根据需要创建一个URL数组,然后使用请求函数映射该数组,如下所示:
let rp = require('request-promise');
let urls = ['http://...', 'http://...'];
let promises = urls.map(rp);
然后使用Promise.all
等待所有这些内容完成,同时完成:
Promise.all(promises)
.then(...)
.catch(...);
或者,如果您正在使用async / await,那么:
try {
let x = await Promise.all(promises);
...
} catch (err) {
...
}
如果您正确运行,axios
或request-promise-json
或request-promise
等许多模块都会为您解析JSON,请参阅:
避免自己解析JSON,但如果你这样做,总是将JSON.parse()
放在try/catch
内(或使用我的小tryjson
模块) - 请参阅知道原因: