[英]setTimeout in call to API endpoint not returning values
我試圖調用Yelp API中的另一個端點,以提取業務描述信息和營業時間。 我在Express中定義了初始POST路由,並使用ejs在調用第一個端點時能夠顯示數據。 我需要將業務ID從在第一個端點中創建的數組傳遞給對第二個端點的調用,但是我收到TooManyRequests
響應,因此必須使用setTimeout
; 這就是我遇到問題的地方
雖然setTimeout
允許我console.log從第二次調用返回的結果,但實際上不允許我返回任何要顯示在頁面上的數據。 沒有拋出任何錯誤,也沒有返回undefined
,這進一步加劇了我的困惑。
我試圖將setTimeout
包裝在for循環內部和外部的IIFE中,這產生了與以前相同的結果。 我簡短地考慮了實現Promises的問題,但是正在看是否可以僅使用setTimeout
來實現。 不知道我是否在這里使用正確的方法,但是任何幫助或澄清將不勝感激。
app.js
express = require("express");
var app = express();
var path = require("path");
var yelp = require("yelp-fusion");
var request = require("request");
var bodyParser = require("body-parser");
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({extended: true}));
app.set("view engine", "ejs");
let client = yelp.client("API_KEY_HID");
app.get("/", function(req,res){
res.render("landing");
});
app.post("/", function(req, res){
client.search({
term: 'coffee',
location: 'Oakland',
limit: 10
}).then(response => {
var businesses = response.jsonBody.businesses;
var idArray = [];
var openHours;
var id = businesses.forEach(el => {
idArray.push(el.id);
});
for(var x = 0; x < businesses.length; x++){
var delay = 1 * 1000;
setTimeout(function(x){
client.business(idArray[x]).then(response => {
var hours = response.jsonBody.hours.map(el => {
return el.open;
});
openHours = hours.map(lo => {
return lo[x].start;
});
return openHours;
});
},delay*x,x)
}
res.render('search', {
hour: openHours
});
}).catch(e => {
console.log(e);
});
});
app.listen(3000);
這是您看不到任何數據的原因:
then
函數實際上返回一個Promise
。 它使用傳遞給它的函數的返回值解析 ,在本例中為openHours
。
更廣泛地說, client.business(id)
是一個Promise
。 client.business(id).then(resolvingFunction)
也是 Promise
。 如您所知,當client.business(id)
解析時,它執行傳遞給then
的函數。 您不知道的是client.business(id).then
還需要解決 。 您編寫它的方式使用openHours
值openHours
。 為了執行, 它需要自己的.then
。 它需要是client.business(id).then(...).then(openHours=>{do something with openHours})
。 你並不需要兩個then
只要不是在你返回openHours■在這種情況下, then
,你就用它做什么。 解決此問題的最小更改是將res.render
return openHours
當前return openHours
的行。 但是,那會有點混亂。 或者,您可以使用多個promise或使用async
/ await
來做到這一點。
希望這可以幫助。
您的代碼有很多問題。 對於初學者來說, setTimeout()
是異步的並且是非阻塞的。 這意味着您的for()
循環需要設置一組計時器才能完成,您需要在調用任何setTimeout()
回調之前調用res.render('search', {hour: openHours})
,因此openHours
仍然為空。
然后,要解決您遇到的TooManyRequests
錯誤問題,您將不得不重新設計發出請求的方式以及如何監視請求完成的方式。 為了達到最佳效果,您將必須知道從其請求數據的主機的實際請求限制。 您需要知道您是同時限制在飛行中一定數量的並行請求,在特定時間段內限制在一定數量的請求(例如1個請求/秒)還是是否存在其他規則。
在不知道自己實際受到限制的情況下,您可以設計一個串行請求系統(一次請求一個,請求之間的延遲可調)。 您可能會調整為可以與主機強制執行的任何限制一起使用(除非您發出的請求總數過多)。 如果您知道實際的規則,則可以設計更有效的代碼。 但是,在不知道規則的情況下,這是一種可調的,序列化的方法。
另外,代碼中還有許多其他不清楚的部分,因為不清楚所有setTimeout()
回調中您試圖累積的內容。 每個人都將openHours設置為一個新值(覆蓋先前的值),所以我無法確切地說出您想要該數據的外觀。 您將必須在下面的代碼中填寫該部分。
這會序列化您的所有請求,一個接一個地延遲,一個接一個地延遲。 您可以對其進行調整,以將請求的速度減慢到主機可以接受的水平。
此代碼使用.reduce()
設計模式來序列化可在任何環境下工作的承諾。 還有許多其他設計模式可用於序列化基於promise的操作。 如果您有ES7環境,那么在for
循環中進行異步/等待也是一種簡單的方法。
var express = require("express");
var app = express();
var path = require("path");
var yelp = require("yelp-fusion");
var request = require("request");
var bodyParser = require("body-parser");
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({
extended: true
}));
app.set("view engine", "ejs");
// utility delay function that returns a promise
function delay(t, v) {
return new Promise(resolve => {
setTimeout(resolve.bind(v), t);
});
}
let client = yelp.client("API_KEY_HID");
app.get("/", function(req, res) {
res.render("landing");
});
app.post("/", function(req, res) {
client.search({
term: 'coffee',
location: 'Oakland',
limit: 10
}).then(response => {
var businesses = response.jsonBody.businesses;
var idArray = businesses.map(el => el.id);
// set your delay value here between reqeusts (here it is set to 500ms)
const delayBetweenRequests = 500;
return idArray.reduce((id, p, i) => {
return p.then((array) => {
return client.business(id).then(response => {
// not sure what you want to get out of this response and add to the array of openHours
// that we're accumulating
array.push(something here to add to the results);
// return delay promise so the next request will wait
return delay(delayBetweenRequests, array);
});
});
}, Promise.resolve([])).then(openHours => {
res.render('search', {hour: openHours});
});
}).catch(e => {
console.log(e);
res.sendStatus(500);
});
});
app.listen(3000);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.