繁体   English   中英

对API端点的调用中的setTimeout不返回值

[英]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 还需要解决 您编写它的方式使用openHoursopenHours 为了执行, 它需要自己的.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM