簡體   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