My code looks like this,
export function handleLogin(window,userData){
return (dispatch) => {
Meteor.call('checkUserLogin',userData,
(error,result)=>{
if(result.isLogin && !error) {
Meteor.call('SOMECALL',SOMEDATA (e,r)=>{
if(!e) {
async function getData(){ return await getAdminUgData();}
getData()
.then((d)=>{console.log('resolve!!');})
.catch((e)=>{console.log('!!reject'); });
}
});
});
}; }
the getAdminUgData is,
export function getAdminUgData(){
return new Promise((resolve, reject) => {
Meteor.call('adminGetUserGroupData', (e,r)=>{
if(e) reject(new Error('error'));
else resolve(r);
});
});}
I am supposed to print out 'resolve' only because the resolve(r); is confirmed being called in getAdminUgData. But the confusing/weird reality is that 'resolve!!' is printed and after that, '!!reject' is also printed. And I completely have no ideas about this. Any suggestions are welcome; thanks.
No, it's absolutely impossible for the same promise to both reject and fulfill - and so it will never happen that both callbacks to .then(…, …) are called. It is however totally possible that both a .then(…) and a .catch(…) callback are called when chained - notice that this doesn't seem to be the case in your example, it seems there's something else going on.
Related
I'm new to promises, so apologize for the newbie question. Inside my function, I have the following lines (middle of the function):
...
const retPromise = await buildImgs(file, imgArray);
retPromise.then(async function () {
console.log("completed build imgs");
...
My assumption was that the "then" from the promise would not execute until the await was completed. but alas, it is acting like sync code, and the retPromise evaluating the "then" before the buildImgs is completed (as measured by my console.log flows). The result is an undefined retPromise.
please help...what am I missing in the concept?
OK: after feedback, let me explaing further my question:
I am trying to understand this async/sync flow and control concept:
const retVal = somefunc();
console.log(retVal);
const retVal = await somefunc();
console.log(retVal);
in the first case, if I understand sync / async code correctly, then I should have a possibility that retVal is undefined when the console.log finds it...
in the second case, I thought it would stop flow until that point that somefunc() completes, then the flow would continue. However my reading seems to indicate it will still try to run the console.log message as a parallel thread. So this leads me to believe I would need to put the console.log inside of the .then after somefunc. Which leads me to promises. So I made a promise return, which I see happening.
However, the .then, as in my original post code, seems to post the console message "completed build imgs", before code inside my buildImgs completes (measured by time I know the function to take, and also console messages inside the buildImgs to help me with sequencing)
so it seems to me I am still missing a fundamental on how to block flow for async code. :(
When you use await construction the script waits until the promise resolves and return to your retPromise value from this promise.
So in this case better to choose one. Remove await and keep then, or keep await and use retPromise value.
Assuming that buildImgs is actually returning a promise (example)
const buildImgs = (file, imgArray) => {
return new Promise((resolve, reject) => {
try {
// ...
resolve()
} catch (err) {
reject(err)
}
})
}
When you call await on a promise its already waiting for the promise to complete, if you remove the await on the call then you can use .then
there are two ways to write promise handlers, the older way looks like this
buildImgs(file, imgArray)
.then(() => {
console.log('im done')
})
.catch(err => {
console.error(err)
})
and the newer syntax
// you must declare "async" in order to use "await"
const asyncFunction = async () => {
try {
await buildImgs(file, imgArray)
console.log('im done')
} catch(err) {
console.error(err)
}
}
asyncFunction()
if you need the return value from the promise, then you would assign it to a variable
const ineedResponse = await buildImgs(file, imgArray)
console.log(ineedResponse)
// or
buildImgs(file, imgArray)
.then(ineedResponse => {
console.log(ineedResponse)
})
.catch(err => {
console.error(err)
})
With promises, is it bad practice to leave out the use of reject? If I just want to return a Promise to ensure this function is run in it's entirety and not block whatever follows this function.
function testFunc() {
return new Promise((resolve,reject) => {
// do stuff
resolve(true);
})
}
testfunc().then(() => { // additional stuff});
If there is a chance of the do stuff throwing an error, then you should make sure to use reject and call it in case there's an error, so that the caller can see that there was a problem and (hopefully) handle it appropriately. For example, you wouldn't want to do:
function testFunc() {
return new Promise((resolve,reject) => {
getApi((error, result) => {
resolve(result);
});
});
}
but instead
function testFunc() {
return new Promise((resolve,reject) => {
getApi((error, result) => {
if (error) reject(error);
resolve(result);
});
});
}
If there's really no chance of the contents of the function erroring (barring logic bugs that could be unknowingly present in any code), then reject won't help you, because you don't really have any place suitable to put it. For example:
function someWeirdPromiseFunctionThatBlocks() {
return new Promise((resolve) => {
for (let i = 0; i < 1e5; i++) {
}
resolve();
});
}
Note that if you just want to:
not block whatever follows this function.
then just returning a Promise won't accomplish that, because the Promise constructor will run all of its code synchronously until it encounters something asynchronous (like getApi). To avoid blocking the running of sync code below, use Promise.resolve or setTimeout, eg:
function testFunc() {
return Promise.resolve()
.then(() => {
// do other stuff
});
No, its not necessary at all. reject is meant to be used in a similar way as one might use throw - it's for errors that happen.
In fact, if you're familiar with javascript's async/await syntax, this async function...
async function doSomething() {
throw new Error('Oh no!')
}
...roughly translates to this:
function doSomething() {
return Promise.reject(new Error('Oh no!'))
}
which shows how reject is intended to be used wherever you might normally throw an error.
Here's an example promise that I use often where there isn't any "reject" that would make sense:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
wait(1000).then(() => console.log('done'))
Many others such examples exist.
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();
There seems something inherently wrong with having to define a Promise's callback as asynchronous:
return new Promise(async (resolve, reject) => {
const value = await somethingAsynchronous();
if (value === something) {
return resolve('It worked!');
} else {
return reject('Nope. Try again.');
}
});
This is apparently an antipattern and there are coding problems which can arise from it. I understand that it becomes easier to fail to catch errors here, even when placing await statements inside try/catch blocks.
My first question is, what's the best way to code something like this, when one wants to forward a Promise with different resolve/reject values? With then/catch? I.e.
return new Promise((resolve, reject) => {
somethingAsynchronous().then(value => {
if (value === something) {
return resolve('It worked!');
} else {
return reject('Nope. Try again.');
}
}); // errors would now be propagated up
});
Or do you just take it out the Promise constructor altogether as suggested here?
async function outerFunction() {
const value = await somethingAsynchronous();
return new Promise((resolve, reject) => {
if (value === something) {
return resolve('It worked!');
} else {
return reject('Nope. Try again.');
}
});
}
But what if you have several await statements in the outerFunction(), i.e. a linear code block calling several asynchronous functions. Would you then have to create and return a new Promise every time?
But then how do you account for code such as this?
async function outerFunction() {
if (someSynchronousCheck()) {
return 'Nope. Try again.' // another reject case
}
const value = await somethingAsynchronous();
// ...
}
I have the feeling that I'm making this more complicated than it should be. I'm trying to avoid nesting callbacks/chaining then/catch blocks without creating more problems in the future.
My final question is, why is the callback passed to a Promise not inherently async? It is already wrapped within a promise and expects the resolve/reject functions to be called asynchronously.
You do this:
async function outerFunction() {
const value = await somethingAsynchronous();
if (value === something) {
return 'It Worked!';
}
throw Error('Nope. Try again.');
}
Using async wraps the result of outerFunction with a Promise.
If you want that wrapping promise to resolve to something, just return it from the async function. If you want the wrapping promise to be rejected, throw an error inside the async function.
But then how do you account for code such as this?
async function outerFunction() {
if (someSynchronousCheck()) {
throw Error('Nope. Try again.');
}
const value = await somethingAsynchronous();
// ...
}
new Promise(async (resolve, reject) => { ... }) is relatively new antipattern. It results in creating 2 promise objects instead of 1, uncaught errors that happen inside constructor cannot be caught with try..catch and result in unhandled rejection.
Considering that promise asynchronous code can be handled with async..await, current use case for Promise constructor is non-promise asynchronous code, e.g.:
new Promise(resolve => setTimeout(resolve, 1000))
When Promise constructor contains synchronous code or involves other promises, a promise should be constructed with async function. A drop-in replacement is async IIFE:
return (async (resolve, reject) => {
const value = await somethingAsynchronous();
if (value === something) {
return 'It worked!';
} else {
throw 'Nope. Try again.';
}
})();
If the need for Promise constructor still presents when being used together with async, Promise constructor should be moved down in hierarchy so it won't wrap any async function.
My final question is, why is the callback passed to a Promise not inherently async? It is already wrapped within a promise and expects the resolve/reject functions to be called asynchronously.
async function isn't just a function that is executed asynchronously, it returns another promise that is supposed to be utilized - or at least handled with catch. Promise isn't supposed to utilize a promise that is returned from constructing function.
The constructor can resolve on same tick and doesn't necessarily have to be asynchronous.
Promise.resolve(1);
is similar to
Promise(resolve => resolve(1))
and not to
Promise(resolve => setTimeout(() => resolve(1)))
You can also chain the promises yourself by simply doing this:
return new Promise((resolve, reject) => {
somethingAsynchronous().then((value) => {
if (value === something) {
return resolve('It worked!');
} else {
return reject('Nope. Try again.');
}
}, (error) => { reject(error); });
});
I've been using this for some time and it works perfectly for me.
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!