The Problem
I've got a route (/mediumData) that gets called on every page reload of a website. Here is the express router handler for the route:
router.get("/mediumData", (request, response) => {
getMediumData
.then(mediumData => {
response.json(mediumData)
})
.catch(error => {
response.send(error)
})
});
The issue I'm running into is that the promise getMediumData only gets called when the server restarts, and not on every page load like intended.
What I've Tried
When I've tried debugging the code with console.log statements, I found out that the console.log was being executed inside of the getMediumData.then handler (on page refreshes). However, the getMediumData promise would not execute any console.log statements on page refreshes (only on server restarts would the console.log be executed).
Here is an example of what I'm talking about regarding my console.log debugging:
getMediumData.then handler
router.get("/mediumData", (request, response) => {
getMediumData
.then(mediumData => {
console.log("This text gets outputted on every page refresh.");
response.json(mediumData)
})
.catch(error => {
response.send(error)
})
});
getMediumData promise
const getMediumData = new Promise((resolve, reject) => {
console.log("This text only gets outputted on server restarts.");
https
.get(
// Some stuff...
)
});
Promises can only be resolved/rejected once, it's just how they work. So a simple solution here would be to wrap your existing getMediumData promise in a function that creates a new promise for every request.
For example:
const getMediumData = () => new Promise((resolve, reject) => {
https
.get(
// Some stuff...
)
});
router.get("/mediumData", (request, response) => {
getMediumData().then(mediumData => {
response.json(mediumData)
}).catch(error => {
response.send(error)
});
});
The code wrapped by the getMediumData promise executes only once. To execute it in every request, you could move the assignment (i.e. getMediumData = new Promise(...) into the body of the route.
Alternatively, you can wrap the promise creation logic into a function returning a new promise each time and use that function in the route.
const getMediumDataPromise = () => new Promise(
(resolve, reject) => {
console.log("This text only gets outputted on server restarts.");
https
.get(
// Some stuff...
)
}
);
router.get("/mediumData", (request, response) => {
getMediumDataPromise()
.then(mediumData => {
console.log("This text gets outputted on every page refresh.");
response.json(mediumData)
})
.catch(error => {
response.send(error)
})
});
Related
I have a problem with promises. The point is that the one function isn't completed and the executing code is jumping to then method.
const load = (function() {
const site = function(url, parent) {
return fetch(url)
.then(response => {
return response.text()
})
.then(data => {
parent.innerHTML = data;
})
};
return {
site: site,
};
})();
function mainApp() {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log(document.querySelector('.content'));
const welcome = document.createElement('div');
const content = document.querySelector('.content');
welcome.textContent = `Welcome, ${user.displayName}`;
content.appendChild(welcome);
} else {
}
});
}
function promise() {
return new Promise((resolve, rejected) => {
load.site('pages/main/main.html', content);
//this function isn't completed and executing code is jumping to then
})
}
promise().then(() => {
console.log('then');
mainApp(); //this function is called before the upper code is completed
});
And because of this bug I can't change the DOM in mainApp function because this function is completed before the load function (which is also changing to DOM by using fetch). My goal is to firstly call and complete load.site() and then mainApp() but I don't know what's happening now and where is the problem.
I assume that you assumed that we assume that you resolved the function like
function promise() {
return new Promise((resolve, rejected) => {
load.site('pages/main/main.html', content);
resolve(); // Like this.
})
}
The Problem
When you call promise. It calls load.site and then resolves. So why isn't it giving the expected behavior.
Well, the problem is that load.site is a synchronous function, so it does not wait for the fetch call and returns which resolves promise before fetch is resolved. So, the code in promise.then() runs before the code in fetch.then()
The Solution
Make load.site an asynchronous function so that it returns a promise that can be awaited. i.e.
const site = async function (url) {
return fetch('a.js')
.then(response =>{
return response.text()
})
.then(data =>{
console.log("Loaded");
})
};
Then make the promise's executor async so that you await load.site. i.e.
function promise() {
return new Promise(async (resolve, rejected) => {
await load.site('pages/main/main.html'); // This line does the magic
resolve();
});
};
This will make sure that your promise resolves after fetch has resolved. So that you can get the expected behavior.
Hope it helps. Keep on coding
I am trying to use promises. Basically puting http connections in one js and calling from another js. But I am not able to do so. What's the mistake here?
http.js
'use strict';
const fetch = require('node-fetch');
module.exports.get = async (url) => {
console.log("inside get method");
const promise = new Promise(function (resolve, reject) {
console.log("inside promise");
fetch(url)
.then(res => {
console.log("inside fetch");
resolve(res.json());
})
.catch(json => reject(Error(json)));
})
return promise;
}
main.js
'use strict';
const http = require('/opt/http.js')
module.exports.httpTest = async (event) => {
let url = 'http://www.someurl.com/';
console.log("calling get method");
http.get(url).then(
function (data) {
console.log("inside http then")
console.log(data);
}).catch(function (data) {
console.log(data);
});
console.log("exited get method");
}
As you can see in http.js I have written a wrapper for GET request which I am trying to use in main.js.
When I execute main.js, nothing fails, but not get displayed on console. What I am doing wrong here?
UPDATE
I have added console logs everywhere... and when I call httpTest from anywhere, here is what I am getting
calling get method
inside get method
inside promise
exited get method
basically it's not going inside fetch
Don’t create a useless extra promise.
// this is a code smell
const promise = new Promise(function (resolve, reject) {
console.log("inside promise");
fetch(url)
.then(res => {
console.log("inside fetch");
resolve(res.json());
})
.catch(json => reject(Error(json)));
})
return promise;
Just return fetch(url); which already returns a promise. Your wrapper promise adds nothing.
Second, your exited get method is going to run outside the promise chain. If you want that to run after get finishes you need to await the http.get call inside HttpTest.
I'm using a csv-parser npm module to read a csv file, process it, and then create a statistical model based on the data. The issue I'm having is that the other file that uses this isn't waiting for the model to finish before moving on, so it ends up trying to use values/methods that are not yet defined. Based on other posts, this is what I have:
this.read = async function(){
return new Promise((resolve, reject) => {
console.log("in mv read");
fs.createReadStream("./assets/stats-csv.csv")
.pipe(csv({
mapValues: ({ header, index, value }) => this.toNumber(header, value)
}))
.on('data', (data) => this.process(data))
.on('error', err => {
reject(err);
})
.on('end', () => {
this.model();
console.log('finished mv model');
resolve(true);
});
})
}
And then the other file uses the method the following way:
this.train_mv = async function(){
console.log("in train mv wrapper")
const success = await this.mvReg.read();
return success;
//console.log(success);
}
I added the "success" bit just to see if returning and using a value from the promise would help, but it doesn't. The function just moves on and doesn't even go to the "return success" line. Am I missing something about async/await? Shouldn't the train_mv function pause and wait until the promise resolves? I would appreciate any help. Thanks!
Code:
var promiseResolve, promiseReject;
function iterateRules(rules, params, i = 0) {
CWevents.putRule(rules[i], function(err, data) { // This is an async function with a callback
if (err) console.log(err); promiseReject(err)
responses++
params['Lambda_invoke']['SourceArns'].push(data.RuleArn)
if(responses == rules.length){ promiseResolve("Success"); console.log("Resolved")}
// After two responses are confirmed, this if does run and I get the "Resolved"
})
i++
if(i < rules.length){
setTimeout( function(){
iterateRules(params['CW_rules']['Rules'], params, i)
}, 50)
}
}
new Promise((resolve, reject) => {
resolve()
// This part is added solely for the code to make sense, it's taken out of a
// bigger script and lots of unnecessary data is removed
})
.then((Item) => {
return new Promise((resolve, reject) => {
promiseReject = reject;
promiseResolve = resolve;
iterateRules(params['CW_rules']['Rules'], params)
})
}) .then((res) => {
console.log("This ran")
})
The iterateRules function is supposed to run an asynchronous function multiple times, and resolve the Promise it's called in when the last response is acquired. The if(responses == rules.length) does run as expected and logs the "Resolved" in the console. Everything is successful, no errors.
Beneath is the context of this code, the iterateRules function is executed, but the .then that comes after, isn't. If I put a resolve() inside the promise directly, it does execute. What might be wrong with this script? I tried running a simple version of it that looks like this separately:
var res, rej;
function dude(){
res()
}
new Promise((resolve, reject) => {
res = resolve;
dude()
}).then((dude) => {
console.log("resolved")
})
And it does in fact work, so I'm very confused. What might cause the problem?
I would make iterateRules() return a promise (since it is asynchronous). I would also promisify the CWevents.putRule() function so you can accomplish some code like the below:
function iterateRules(rules, params) {
return Promise.all(rules.map(rule => {
return CWevents.putRule(rule)
})).then((data) => {
params['Lambda_invoke']['SourceArns'].push(data.RuleArn)
})
}
Then your handler for iterateRules would become:
iterateRules(rules,params).then(()=>{
// Do something...
})
I am working on a search bar which calls an API when user starts typing. One each key stroke, there is a request to server and it returns the response.
I want to reject previous promises before making the new call to the server, how can I achieve that? Right now I have the issue of old promises coming back and changing the UI which makes it to flicker.
export const makeGetPlaceData = (axios, uri) => (name, country) => {
const promise = new Promise((resolve, reject) => {
axios.get(`${uri}?name=${name}&country=${country}`)
.then(response => {
setTimeout(() => resolve(response), 2000);
})
.catch(error => {
console.log('rejected', error);
reject(error);
});
});
return promise;
};
using setTimeout to simulate a slow network response.
I generally do this at the handler level instead of the promise level. The gist of it is you keep track of how many calls you've done, and each callback knows its call number. When the promise resolves, if the callback is no longer the most recent, return early.
let lastCallId = 1;
function doCall() {
var myCallId = lastCallId;
lastCallId++;
api.doSomething().then((data) => {
if (myCallId !== lastCallId) return;
// Do something with the data
});
}