Could someone help me why the promise within the promise.all i.e ( suggestRC and suggestGL) are not getting called? I would like to make sure the suggestRC and suggestGL are executed concurrently. That was the reason, I had written like this. extractIdeas is getting called but suggestRC and suggestGL are not getting called.
function suggestValues(editIdeaPanel) {
Requests.deckreposvc({searchIdeas: {searchString: searchReq}})
.then(extractIdeas)
.then(Promise.all([suggestRC, suggestGL]))
.catch(handleError);
}
function extractIdeas(searchRes) {
return searchRes.searchIdeas.data;
}
function suggestRC(ideas) {
return new Promise(function(resolve, reject) {
//do something
}
resolve(ideas);
});
}
function suggestGL(ideas) {
return new Promise(function(resolve, reject) {
if(!editIdeaPanel.wdGLeaderCombo.propertyValue.uuid) {
//do something
}
resolve(ideas);
});
}
You need to call those two functions (add parentheses) in a callback that you pass to then:
.then(data => Promise.all([suggestRC(data), suggestGL(data)]))
Also, you will want suggestValues to return the promise:
return Requests.deckreposvc( //...etc
Related
I have a function called "test_sheet" that is supposed to return a value. that value will then be passed to a tester function which will tell me if I passed or failed the test.
inside my "test_sheet" I have a few async operations which are handled by promises.
now, how can I return a (non-promise) value from my test_sheet function.
function test_sheet()
{
//all my logic will go here
new Promise(function(resolve, reject)
{
//simulating an async operation
setTimeout(() => resolve(true), 1000);
})
.then(function(res){return res});
}
function tester()
{
//not allowed to change this function in any way
if(test_sheet() == true)
console.log("pass!");
else
console.log("fail!");
}
tester();
Is there any better way of doing this?
Well, technically it is possible, tester() may reamain intact:
var test_sheet=false;
function start_test()
{
//all my logic will go here
new Promise(function(resolve, reject)
{
//simulating an async operation
setTimeout(() => resolve(true), 1000);
})
.then(res => {
test_sheet=true;
tester();
});
}
function tester()
{
//not allowed to change this function in any way
test_sheet == true ? console.log("pass!") : console.log("fail!");
}
//tester();
start_test();
But the test starts with start_test() now, and test_sheet became a variable, with the sole purpose of acting as an argument - which could not be added to testing() without modifying it.
A nonworking bad design is transformed to working bad desing this way.
test_sheet() always returns a promise so try to get it resolved using async await or .then which feeds into the tester() function.
call you function this way:
test_sheet().then(function(test_sheet){
tester(test_sheet)})
for this you need to pass the boolean return value from test_sheet() to tester(test_sheet)
If you handle asynchronous code you have to use promise or callback and handle with async/await to change them to synchronous code
For example
function test_sheet()
{
//all my logic will go here
return new Promise(function(resolve, reject) {
//simulating an async operation
setTimeout(() => resolve(true), 2000);
})
}
async function tester()
{
//not allowed to change this function in any way
await test_sheet() == true ? console.log("pass!") : console.log("fail!");
}
tester();
I use the following code and there is something that a bit confuse me
if I put in the timeout 1000ms I see that the promise called in the right order
but if I change it to the following
This is step 3
This is step 2
This is step 1
I guess that this happen since when the function is resolved then he proceed to the next function am I correct ? if this is true how can I do this chain that when the first is finished then he proceed to the second etc but without using the promise hell :-)
https://jsfiddle.net/2yym400j/
var step1 = function(ms) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("This is step 1");
resolve();
}, ms);
})
}
var step2 = function(ms) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("This is step 2");
resolve();
}, ms);
})
};
var step3 = function(ms) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("This is step 3");
resolve();
}, ms);
})
};
step1(500)
.then(step2(300))
.then(step3(200))
.catch(function(err) {
console.log(err);
});
Just pass a function instead of the result of the steps.
step1(500)
.then(function() { return step2(300); })
.then(function() { return step3(200); })
.catch(function(err) {
console.log(err);
});
Without this, you are just calling each step without "blocking" for the previous step to resolve.
I know you've already gotten an answer as to why your original code didn't work, but I thought I'd show another way to approach it that is a bit more DRY than what you were doing. You can create a single function that returns a function and then you can use that in the fashion you were using because it returns a function that will be called later which is what .then() wants. So, you can do something like this:
function delay(t, msg) {
return function() {
return new Promise(function(resolve) {
setTimeout(function() {
console.log(msg);
resolve();
}, t);
});
}
}
delay(500, "This is step 1")()
.then(delay(300,"This is step 2"))
.then(delay(200, "This is step 3"))
.catch(function(err) {
console.log(err);
});
Working demo here: https://jsfiddle.net/jfriend00/mbpq4g8m/
Daniel White's comment and answer are correct, but I thought an additional explanation might help.
Your original code broke two rules:
then can't take a Promise, but it can take a function that returns a Promise. If you pass in anything except a function, it will be ignored, just like you passed in null instead.
As soon as you call new Promise(someFunction), the someFunction executes asynchronously without waiting for anything. This means you can call new Promise from within a then function, but if you call it early then it won't have the delayed behavior you're expecting.
So given that each call to stepN returns a newly-constructed promise, I've inlined everything that happens synchronously and renamed the results constructAndReturnPromiseN and constructedPromiseThatStepNReturns. That makes your original code looks like this so all the promises happen at once:
constructedPromise1ThatStep1Returns
.then(constructedPromise2ThatStep2Returns) // BAD: Don't pass promises into then.
.then(constructedPromise3ThatStep3Returns) // BAD: Don't pass promises into then.
.catch(function(err) {
console.log(err);
});
...where Daniel White's code does this:
constructedPromise1ThatStep1Returns
// GOOD: The then function returns a promise that is *constructed inside* the function.
.then(function() { return constructAndReturnPromise2(300); })
.then(function() { return constructAndReturnPromise3(200); })
.catch(function(err) {
console.log(err);
});
I am really hoping someone can help me with this issue despite my inability (confidentiality issues) to share too much information. Basically, I wrote this function to retry failed promises:
function retryOnFailure(func) {
return func().then(function(resp) {
return resp
}, function(err) {
return setTimeout(function() {
return retryOnFailure(func)
}, 5000)
}
)}
And then I have this code to utilize it:
function getStuff() {
return $.get('/some/endpoint')
}
retryOnFailure(getStuff).then(function(res) { console.log(res) })
Now the recursive retry function works fine, but my then in the last line of code doesn't fire in the event that an error case is reached in retryOnFailure. I know that the reason is because each recursive call creates a new promise so the promise that I'm listening to in my last line is not the same one that gets resolved, but I'm having difficulty figuring out how to remedy this. I want this function to be a generic retry function and as such don't want to handle the actual success in the method, but I'm not seeing any other way. Any help would be greatly appreciated!
return setTimeout(function() {
return retryOnFailure(func)
}, 5000)
looks like you're trying to do the right thing - return the next result from your .catch callback. However, setTimeout does not return a promise, so retryOnFailure() will be resolved immediately (with the timeout cancellation id).
Instead, you need to make sure that for all asynchronous functions that you use a promise is produced, so let's start by promisifying setTimeout:
function delay(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, ms);
});
}
Now we can use that to chain the retry after a delay, and get a promise from it:
function retryOnFailure(func) {
return func().then(null, function(err) {
return delay(5000).then(function() {
return retryOnFailure(func);
});
});
}
Notice that instead of .then(null, …) you can also use .catch(…).
This is the first way that came to mind, there is probably a more elegant solution:
function retryOnFailure(func, onSuccess) {
return func().then(function(resp) {
onSuccess(resp);
}, function(err) {
return setTimeout(function() {
return retryOnFailure(func, onSuccess)
}, 5000)
}
)}
retryOnFailure(getStuff, function(res) { console.log(res) });
The problem is your call to setTimeout, it breaks the flow of your promise. Try something like this instead:
function retryOnFailure(func) {
return new Promise(function(resolve) {
func().then(function(resp) {
resolve(resp);
}).catch(function(err) {
setTimeout(function() {
retryOnFailure(func).then(resolve);
}, 5000)
});
});
};
retryOnFailure(getStuff).then(function(res) { console.log(res) });
Note how I've created a new promise inside the function which never throws an error, but instead will simply attempt to process the func() and recurse itself on failure.
It also may be a good idea to put some kind of retry-limit as well.
Good luck!
I have a promise chain with a recursive promise doAsyncRecursive() in the middle like so:
doAsync().then(function() {
return doAsyncRecursive();
}).then(function() {
return doSomethingElseAsync();
}).then(function(result) {
console.log(result);
}).catch(errorHandler);
doAsyncRecursive() has to do something and if it at first does not succeed, i then after want to try every 5 seconds until it does. This is what my promise function looks like:
function doAsyncRecursive() {
return new Promise(function(resolve, reject) {
//do async thing
if (success) {
resolve();
} else {
return new Promise(function(resolve, reject) {
setTimeout(function() {
doAsyncRecursive();
}, 5000);
});
}
});
}
But when I execute, the chain does not continue after doAsyncRecursive() is successful on the 2nd try and resolve() is called (it continues if the attempt is successful on the 1st try however).
What pattern do I need to make this work?
Catch the failure, wait five seconds, then try again.
function doAsyncRecursive() {
return doAsyncThing().catch(function() {
return Promise.delay(5000).then(doAsyncRecursive);
});
}
Here doAsyncThing is a function corresponding to the //do async thing comment in the OP's code, defined as returning a promise. In the original code, the success or failure of the "do async thing" is tested using a success flag, but by definition asynchronous routines do not deliver such a flag; they deliver their results either via a callback or a promise. The code above assumes that doAsyncThing returns a promise. It also assumes that "failure", in the sense of "does not return the response i want", is represented by that promise rejecting. If instead "success" or "failure" is to be defined as some particular value of a fulfilled promise, then you'd want to do
function doAsyncRecursive() {
return doAsyncThing().then(function(success) {
if (success) return success;
else return Promise.delay(5000).then(doAsyncRecursive);
});
}
Say I have the following Promise chain:
var parentPromise = Promise.resolve()
.then(function () {
var condition = false;
if (condition) {
return parentPromise.cancel('valid reason');
} else {
return Promise.resolve()
.then(function () {
var someOtherCondition = true;
if (someOtherCondition) {
console.log('inner cancellation');
return parentPromise.cancel('invalid reason');
}
});
}
})
.catch(Promise.CancellationError, function (err) {
console.log('throwing');
if (err.message !== 'valid reason') {
throw err;
}
})
.cancellable();
The above never enters the catch.
If we swap condition to true, the inner cancellation is never hit, but the catch is still not triggered.
removing the .cancellable at the end , and replacing all instances of parentPromise.cancel() with explicit throw new Promise.CancellationError() "fixes" the problem. What I don't understand is why?
Why was the original approach not working?
I am using bluebird 2.3.11.
cancellable() creates cancellable promises and only they throw CancellationError by default, when cancel function is called with out any reason.
In your case, you are making the promise cancellable only after attaching the catch handler. But the promise is not cancellable yet. So, cancel function call will not raise Promise.CancellationError.
You need to change the structure of the code, like this
then(function(..) {
...
})
.cancellable()
.catch(Promise.CancellationError, function (err) {
...
});
Note: I would recommend promising with its beautiful Promise constructor function. It is similar to the ECMA Script 6 specification.
new Promise(function(resolve, reject) {
...
});