Reputation: 53
I am developing a nodejs application that needs to get settings from an array(in a settings object), call a rest api based on the settings and write the response to mongodb and repeat this for the next setting in the array.
Here is a simplified version of the application
var setting //global
process(){ //top level function
for(let s of config.settings){
setting = s;
getData();
}
}
function getData(){
init()
.then(makeRequest) // constructs and makes the rest api call
.then(insert) // writes the response to the db
.catch(function(err){
// logs err
}
}
Running it, only the data for the last setting (in the array) is written to the db and this happens for each iteration. Basically the same data is written on the db for as many iterations. The problem I can see from this is that the for loop finishes executing, before the promises return with the value. I have seen some examples of async.for Any suggestions on fixing this. How do you go about designing this kind of a flow?
Upvotes: 2
Views: 225
Reputation: 6282
You should return an object or array that you can use to store an internal state for your request. Please see the example for how it works.
Also never set a global variable to store your state, with your function being asynchronous the value may not be what you expect it to be.
With this approach you are passing { init }
for the first promise, then { init, request }
for the next so you have the response from each part of your promise chain that you can use to make further requests.
// return an object to store the state on init
const init = () =>
new Promise((res, rej) => res({
init: 'initted'
}))
// pass init and the request to the next function in the chain
const makeRequest = ({ init }) =>
new Promise((res, rej) => res({
init,
request: {
msg: 'this is the response',
id: 33
}
}))
// insert stuff from the request
// then return the data to the next query
const insert = ({ init, request }) =>
new Promise((res, rej) => res({
request,
init,
created_at: Date.now()
}))
const trace = name => x => (console.log(name, x), x)
function getData(){
return init() // return your promise so you can chain it further
.then(trace('after init'))
.then(makeRequest)
.then(trace('after request'))
.then(insert)
.then(trace('after insert'))
.catch(console.error)
}
// call you function
getData()
// since the promise is returned we can continue the chain
.then(state => console.log({ state }))
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>
Upvotes: 2
Reputation: 4122
All of your loop will have executed by the time the callbacks are coming in. So settings
will be the last value.
Instead of relying on globals, pass setting into getData, for example.
Upvotes: 1
Reputation: 151
You can bind the settings to each function call to preserve the value. looks like you'd have to refactor though as the value would be passed in as an argument though i'm not sure if your code is pseudo code or actual code.
async await would work as well but would take longer as it would pause execution at each api call.
Upvotes: 2