Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodejs: How to use async/await when trying to rate limit number of requests to the server

I am trying to use the geocode API to get the json object by limiting the number of requests to 1 per second. I need to use async/await and this is what I have

const requester = {
    lastRequest: new Date(),
    makeRequest: async (url) => {
        var timestart = new Date()
        // first check when last request was made
        var timeSinceLast = (timestart).getTime() - this.lastRequest.getTime();
        if (timeSinceLast < 1000) {
            await new Promise(resolve => setTimeout(resolve, timeSinceLast));
        }
        const response = await fetch(url);
        const json = await response.json();
        return json;
        // make request here and return result
    }
};
var requestResponse = requester.makeRequest('https://geocode.xyz/?
     locate=Warsaw,Poland&json=1')

With this I am getting the following errors:

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'getTime' of undefined

UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)

I tried to find why this is happening and when just print the requester object, I don't get the gettime() undefined error. Am I using async/await and promises correctly? What am I doing wrong?

EDIT: Based on the answers below, I no longer see the error, however I see 'Request Throttled'

const requester = {
   lastRequest: new Date(),
   makeRequest: async function(url){
       var timestart = new Date()
       // first check when last request was made
       var timeSinceLast = (timestart).getTime() - this.lastRequest.getTime();
       if (timeSinceLast < 1000) {
           await new Promise(resolve => setTimeout(resolve, timeSinceLast));
       }
       const response = await fetch(url);
       const json = await response.json();
       return json;
       // make request here and return result
   }
};
requester.makeRequest('https://geocode.xyz/?locate=Warsaw,Poland&json=1') 
.then(console.log) 

This is what I am seeing now:

{ success: false,
 error: { code: '006', message: 'Request Throttled.' } }

Do I need to await for the response?

like image 979
Nikhil Avatar asked Nov 18 '25 04:11

Nikhil


2 Answers

Arrow functions don't have this, so this.lastrequest.getTime is undefined.

Use a normal function instead:

const requester = {
    lastRequest: new Date(),
    makeRequest: async function(url){
        var timestart = new Date()
        // first check when last request was made
        var timeSinceLast = (timestart).getTime() - this.lastRequest.getTime();
        if (timeSinceLast < 1000) {
            await new Promise(resolve => setTimeout(resolve, timeSinceLast));
        }
        const response = await fetch(url);
        const json = await response.json();
        return json;
        // make request here and return result
    }
};
requester.makeRequest('https://geocode.xyz/?locate=Warsaw,Poland&json=1') //Don't write strings in two lines
.then(console.log)

And if you add a then(console.log), you can see the result!

like image 72
FZs Avatar answered Nov 19 '25 17:11

FZs


Don't use => arrow functions inside object methods as the this is not what you think it is.

The this within the arrow function is the one that was in the current context where you defined the object, in your case it is pointing to the global object which has no lastRequest property.

That is why this.lastRequest is evaluating to undefined.

You need to replace it with an anonymous function to correctly point to the this.lastRequest property.

Also you won't get the data you want by simply returning it from the object method and assigning it to a variable as the value returned from your method is wrapped in a promise (due to the async keyword) so you need to call then on it to actually capture the data from the service.

const requester = {
    lastRequest: new Date(),
    makeRequest: async function(url) {
        var timestart = new Date();
        // first check when last request was made
        var timeSinceLast = timestart.getTime() - this.lastRequest.getTime();
        if (timeSinceLast < 1000) {
            await new Promise(resolve => setTimeout(resolve, timeSinceLast));
        }
        const response = await fetch(url);
        const json = await response.json();
        return json; //wrapped in a promise
        // make request here and return result
    }
};
var requestResponse = requester.makeRequest('https://geocode.xyz/?locate=Warsaw,Poland&json=1').then((data)=>{
   console.log(data);
})

Some resources to look at:

Arrow functions as object methods

Async function

like image 28
Fullstack Guy Avatar answered Nov 19 '25 17:11

Fullstack Guy