Recursive promise not resolving - javascript

I have a function that fetches some data. If data is not available (it becomes available after some short time), it returns null. I created a function, that returns promise, which is wrapped around logic that fetches data and checks if it is is available - if not, it calls itself:
Foo.prototype.fetchDataWrapper = function () {
return new Promise((resolve, reject) => {
const data = fetchData();
if (data) {
resolve(data)
} else {
setTimeout(() => {
return this.fetchDataWrapper()
}, 100)
}
})
}
Problem is, that despite data is fetched correctly, this promise never resolves. What am I doing wrong?

Your return this.fetchDataWrapper() is returning from the timer callback, no fetchDataWrapper. fetchDataWrapper has already returned. Instead, pass that promise into resolve:
Foo.prototype.fetchDataWrapper = function () {
return new Promise((resolve, reject) => {
const data = fetchData();
if (data) {
resolve(data);
} else {
setTimeout(() => {
resolve(this.fetchDataWrapper()); // *****
}, 100);
}
})
};
When you pass a promise to resolve, it makes the promise resolves belong to resolve or reject based on the promise you pass to it.
(I've also added some missing semicolons to that code. I recommend being consistent with semicolons: Either rely on ASI or don't, both don't mix the two. Also recommend not relying on ASI, but that's a style choice.)
Side note: It would probably make sense to reject after X attempts, perhaps:
Foo.prototype.fetchDataWrapper = function (retries = 5) {
// *** Declare retries param with default -^^^^^^^^^^^
return new Promise((resolve, reject) => {
const data = fetchData();
if (data) {
resolve(data);
} else {
if (retries) { // *** Check it
setTimeout(() => {
resolve(this.fetchDataWrapper(retries - 1));
// *** Decrement and pass on -^^^^^^^^^^^
}, 100);
} else {
reject(); // *** Reject
}
}
})
};

Related

A .then doesn't run after the promise gets resolved on AWS Lambda

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...
})

JavaScript | Access the object of a Promise from another Promise

In my AngularJS Application, I want to access the return value of a Promise, which I access from a service outside of my controller and import it there. This Promise, return an object. I want to access that objects and properties inside it.
I created the service to get that endpoint. Look below:
export const getEndpoints = () => {
const options = {
method: httpMethod.GET,
url: endpoint.ENVIRONMENT,
};
return Instance(options);
};
The above service in return reads an endpoint which I provide and uses axios on the background. This part is working just fine.
Then imported it, on my angular Controller:
import { getEndpoints } from './config/service';
Finally I created this function:
$scope.isItAvailable = false; // I will use this later to check the actual value. It is not important in the scope of the question..
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
resolve(getEndpoints)
console.log(getEndpoints)
})
}
// And in my main function I am just calling the above
const mainFn = () => {
checkIfItIsAvailable()
// Along with a few others..
}
Actual Results
Now, in my console, I get the functioncheckIfItAvailable printed out.
Expected Results
I instead want to print to the console, the actual value that is being returned by the original promise, the object, and its properties.
Probably You need to call that function instead of just passing it as a parameter.
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
resolve(getEndpoints()) // here
console.log(getEndpoints())
})
}
Then to get that resolved later in your main function, or wherever - just use then:
const mainFn = () => {
checkIfItIsAvailable().then((result) => {
// do what you need with result here
// $scope.isItAvailable = result probably like this
});
}
Please comment if you need another result. I see at least this issue at the moment.
Also, here is a snipper, illustrating that you need to call it instead of just passing.
// here is an example function which just return some string
function getSomething() {
return 'something'; // it could be a promise also
}
// here is example without calling functions, but just passing:
const promise = new Promise((resolve, reject) => {
console.log('NO CALL: ', getSomething);
});
// here is example with calling, so value is resolved
const promise2 = new Promise((resolve, reject) => {
console.log('CALLED: ', getSomething());
});
Here, getEndpoints is an asynchronous function which returns a Promise, and the way to get a return value from promise is to use then callback. You can do it like this:
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
getEndpoints().then(resultOfEndPoint => {
console.log(resultOfEndPoint);
resolve(resultOfEndPoint);
});
})
}
It's possible to access the resolved result of getEndpoints in checkIfItIsAvailable calling getEndpoints() and using then() function:
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
// call getEndpoints
getEndpoints()
// call then to get a result from getEndpoints
.then(res => {
console.log(res);
// checkIfItIsAvailable will be resolved with
// the result of getEndpoints
resolve(res);
});
});
}

ClearTimeout usage best practice within a promise

I have a question about clearTimeout method (sorry in advance for noob question). I am wondering where is the best place to clearTimeout in this following code? I have a "getResponse()"function which will be called multiple times. I am not sure where would be the best place to put the clearTimeout so that it will clear the timeout as soon as responseTimeout either resolves or rejects.Thanks
function getResponse() {
const responseTimeout = new Promise((resolve, reject) => {
let id = setTimeout(() => {
if (!messageHandled) {
reject(`Timed out to get response`);
}
}, 3000);
});
const responsePromise = new Promise((resolve, reject) => {
// some code which returns response promise
});
return Promise.race([
responsePromise,
responseTimeout
]);
}
Typically, I'll do it in the promise itself and avoid the overhead of two separate promises.
function getResponse(...params) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("Timed out to get response"))
// some code to abort request
}, 3000)
// some code which resolves promise
})
}
Usefully, promises ignore later resolutions and/or rejections after you resolve it the first time. If you can programmatically abort it without firing the resolution logic, this becomes much easier to do, but even if you can't, you can always slap a boolean to block future requests along the way. It also makes it easier to add support for canceling later on, which is also helpful. If you need to also shut down the timeout (in case you're doing some DOM mutation or file reading - you rarely need to do this), you could do something like this:
function getResponse(...params) {
return new Promise((reallyResolve, reallyReject) => {
let resolved = false
let id = setTimeout(() => {
reject(new Error("Timed out to get response"))
abort()
}, 3000)
// I'll use these instead of the `resolve`/`reject` callbacks directly.
function resolve(value) {
if (resolved) return
resolved = true
clearTimeout(id)
reallyResolve(value)
}
function reject(value) {
if (resolved) return
resolved = true
clearTimeout(id)
reallyReject(value)
}
function abort() {
// some code to abort request
}
// some code which resolves promise
})
}
This makes it so I don't have to worry about orchestrating everything, but it still works.
If you don't need abort logic (you only really need it for network requests and similar), this becomes a lot simpler:
function timeout(ms) {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error("Timed out")), ms)
})
}
function getResponse(...params) {
return Promise.race([
timeout(3000),
doSomethingAsync(),
])
}

How to flatten a Promise within a Promise?

I have the following 2 functions, each returns a Promise:
const getToken = () => {
return new Promise((resolve, reject) => {
fs.readFile('token.txt', (err, data) => {
if (err) { return reject(err) }
if (!tokenIsExpired(data.token)) {
return resolve(data.token)
} else {
return requestNewToken()
}
})
})
}
const requestNewToken = () => {
return new Promise((resolve, reject) => {
restClient.get(url, (data, res) => {
fs.writeFile('tokenfile.txt', data.token, err => {
resolve(data.token)
})
})
})
}
function1()
.then(value => {
console.log('taco')
})
.catch(err => {
console.log(err)
})
So function1 runs, and (depending on some condition), it sometimes returns function2, which is returning another Promise. In this code, when function2 is called, the console.log('taco') never runs. Why is this? I thought that if you return a Promise from within a Promise, the resolved value of the nested Promise is what is resolved at the top level.
In order for me to get this to work, I have to do this:
const getToken = () => {
return new Promise((resolve, reject) => {
if (!tokenIsExpired()) {
return resolve(getToken())
} else {
return requestNewToken ()
.then(value => {
resolve(value)
})
}
})
}
That works, but it seems like I'm doing something wrong. It seems like there should be a more elegant way to handle/structure this.
You're right that promises auto-unwrap, but in this case you're returning from inside a promise constructor, which is ignored, you need to invoke either resolve or reject instead of using return. I think this might be the solution you're looking for:
const function1 = () => {
return new Promise((resolve, reject) => {
if (someCondition) {
resolve('foobar')
} else {
resolve(function2());
}
})
}
Inside a promise constructor, you need to call resolve or reject, which are equivalent to using return or throw from inside a then callback.
If you find this distinction confusing (I do), you should avoid the promise constructor entirely by just beginning a new chain with Promise.resolve, like this:
const function1 = () => {
return Promise.resolve().then(() => {
if (someCondition) {
return 'foobar';
} else {
return function2();
}
})
}
const function2 = () => {
return new Promise((resolve, reject) => {
resolve('hello world')
})
}
someCondition = false;
function1()
.then(value => {
console.log(value)
})
With your updated code, I recommend using a library to wrap APIs, rather than accessing the promise constructor yourself. For example, using bluebird's promisify:
const bluebird = require('bluebird');
const readFile = bluebird.promisify(fs.readFile);
const writeFile = bluebird.promisify(fs.writeFile);
const getUrl = bluebird.promisify(restClient.get, {multiArgs:true});
const getToken = () => {
return readFile('token.txt')
.then((data) => {
if(!tokenIsExpired(data.token)) {
return data.token;
} else {
return requestNewToken();
}
});
};
const requestNewToken = () => {
return getUrl(url)
.then(([data, res]) => {
return writeFile('tokenFile.txt', data.token)
.then(() => data.token);
});
};
I've remained faithful to your source code, but I'll note there may be a bug to do with writing data.token, and later trying to read the token property in that file.
Why use a library instead of the Promise constructor?
It allows you to write code which deals only with promises, which is (hopefully) easier to understand
You can be confident that callback APIs are correctly converted without losing errors. For example, if your tokenIsExpired function throws an error, using your promise constructor code, it would be lost. You would need to wrap all of your inner callback code in try {} catch(e) {reject(e)}, which is a hassle and easily forgotten.

Promise.all().then() goes to catch() because then is not recognized

The code is running well until the Promise.all and then is goes right to the catch saying 'then is not defined'.
I've been trying to figure this out without success for hours :(.
Any help are welcome.
Here is a simplified example of code:
// Save
return new Promise((fulfillSave, rejectSave) => {
// Get
this._getObjects().then((object) => {
var promises = [];
// For each value
object.values.forEach((value) => {
promises.push(
// Create promise
new Promise((fulfill, reject) => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
valueMongoDB.save((err, results) => {
if (err) {
reject('Error in saving');
} else {
fulfill();
}
});
})
);
});
// Wait for all promises
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, then((err) => {
// Err
rejectSave(err);
}));
}
}).catch((err) => {
rejectSave(`Error: ${err.message}`);
});
});
Thanks in advance!
Serge.
This is incorrect:
// Wait for all promises
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, then((err) => {
// ^^^^--------------------------- error here
// Err
rejectSave(err);
}));
It's trying to call a freestanding function called then and pass its return value into the then on the object returned by Promise.all.
I think you're trying to hook up a failure handler. If so, you don't say then, you just supply a second function:
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, (err) => {
// Err
rejectSave(err);
}));
But of course, since you're not using the result of that chain and you're just passing the single argument your second function receives into rejectSave, you could just pass rejectSave directly:
Promise.all(promises).then(() => {
// Nothing to do
fulfillSave();
}, rejectSave);
If you told us what your overall code is meant to do and what its inputs are, my suspicion is that that code could be a lot simpler. It's common to create and nest promises unnecessarily, and I suspect that's happening here.
For instance, if you just want to do the saves and get back a promise that will resolve when they're all done successfully or reject on the first failure:
return this._getObjects()
.then(objects => Promise.all(objects.map(value => {
return new Promise((resolve, reject) => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
valueMongoDB.save((err, results) => {
if (err) {
reject('Error in saving');
} else {
fulfill();
}
});
});
})));
Or if we give ourselves a helper function for the Mongo bit:
function mongoSavePromise(value) {
return new Promise((resolve, reject) => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
valueMongoDB.save((err, results) => {
if (err) {
reject('Error in saving');
} else {
fulfill();
}
});
});
}
then:
return this._getObjects()
.then(objects => Promise.all(objects.map(mongoSavePromise)));
Avoid the Promise constructor antipattern!
Your whole code should be a simple
return this._getObjects().then(object => {
var promises = object.values.map(value => {
// Create MDB object + assign value
valueMongoDB.value = value;
// Save
return valueMongoDB.save().catch(err => {
throw 'Error in saving';
});
});
// Wait for all promises
return Promise.all(promises);
}, err => {
throw `Error: ${err.message}`;
});
No unnecessary callbacks, no room for mistakes. Btw, you shouldn't throw strings.

Categories

Resources