Есть много проблем с вашим кодом. Для начала setTimeout()
является асинхронным и неблокирующим. Это означает, что ваш цикл for()
выполняется до завершения установки таймеров, вы вызываете res.render('search', {hour: openHours})
до того, как будет вызван ЛЮБОЙ из setTimeout()
обратных вызовов, и, таким образом, openHours
все еще пуст.
Затем, чтобы решить возникшую ошибку TooManyRequests
, вам нужно будет изменить способ подачи запросов и отслеживания их выполнения. Чтобы сделать это оптимально, вы должны знать, каковы ваши фактические пределы запросов от хоста, с которого вы запрашиваете данные. Вам необходимо знать, ограничено ли вами определенное количество параллельных запросов в полете одновременно, ограничено определенным количеством запросов в течение определенного периода времени (например, 1 запрос / сек) или существует какое-то другое правило.
Не зная, насколько вы на самом деле ограничены, вы можете разработать систему последовательных запросов (один запрос за раз с регулируемой задержкой между запросами). Скорее всего, вы можете настроить это для работы с любыми ограничениями, которые навязывает ваш хост (если вы просто не делаете слишком много общих запросов). Если бы вы знали настоящие правила, вы могли бы разработать более эффективный код. Но, не зная правил, вот настраиваемый, сериализованный подход.
Кроме того, в вашем коде присутствовал ряд других неясных частей, поскольку неясно, что именно вы пытаетесь накопить во всех ваших setTimeout()
обратных вызовах. Каждый из них устанавливал openHours на новое значение (перезаписывая предыдущее значение), поэтому я не мог точно сказать, как вы хотите, чтобы эти данные выглядели. Вы должны будете заполнить эту часть в коде ниже.
При этом все ваши запросы сериализуются один за другим с настраиваемой задержкой между ними. Можно надеяться, что вы сможете настроить ваши запросы на то, чтобы с хостом все было в порядке.
Этот код использует шаблон проектирования .reduce()
для сериализации обещаний, которые работают в любой среде. Существует также много других шаблонов проектирования для сериализации операций на основе обещаний. Если у вас есть среда 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);