Parse .then method and chaining | Syntax eludes me - javascript

Dear stackoverflow community,
I am using application craft as a JS cloud IDE and integrating Parse's cloud database for storage.
I'm writing a subscription service and want to check to see if a user is already subscribed prior to either authenticating their use or prompting them to sign up. Being an asynchronous call I'm trying to utilise Parse's/Promise's .then method to wait for the server's response before proceeding.
I've read the examples and samples on the Parse site (linked before) yet cannot wrap my head around it.
This code functions, and returns the email address if a match is found:
... *Parse declaration etc*
query.find({
success: function(results){
if(results.length>0){
app.setValue("lblOutput", results[0].attributes.email);
}
else{
app.setValue("lblOutput", "No match.");
}
},
error: function(object, error){
console.log(error.message);
console.log(object);
}
});
My attempt at chaining, most recently this:
query.find().then(function(results) {
if(results){
console.log("Within the Then!");
console.log(results);
}
else{
console.log("Could be an error");
}
});
States that method or property 'success' is invalid for undefined. I have attempted to combine the syntax of the first function (success: ... // error: ...) in the chaining attempt unsuccessfully.
Any advice as to how I could
Check to see if an email exists in the Parse DB, then
Wait until the result comes back for further manipulation with another function
would be greatly appreciated.
Once I have .then() figured out there will be further layers of async waiting.
Cheers,
James

Your syntax for handling then is incorrect, it should be:
query.find().then(
function(results) {
console.log("Within the Then!");
console.log(results);
},
function(error){
console.log("Could be an error"+error);
}
);
the then() function takes one or two functions.
the first is a success handler, and the second is an error handler.
query.find().then(success,error)
This snippet is untested but should be pretty close.
var query = new Parse.Query(Parse.User);
query.equalTo(email, "me#me.com");
query.count().then(
function(resultsCount) {
//success handler
if(resultsCount > 0){
doSomeOtherFunction();
}
},
function(error){
//error handler
console.log("Error:"+error);
}
);
If you have more async work to do, your method should look similar to this, remember that when chaining promises the last then() should contain your error handling.
query.find().then(function(result){
doSomethingAsync(); //must return a promise for chaining to work!
}).then(function(result1){
doSomethingAsync2(); //must return a promise for chaining to work!
}).then(function(result2){
doSomethingAsync3(); //must return a promise for chaining to work!
}).then(null,function(error){
// an alternative way to handle errors
//handles errors for all chained promises.
})

Related

Retrying a failed async/promise function?

I have this async block:
test().then(function(result){
// Success: Do something.
doSomething();
}).catch(function(error){
// Error: Handle the error, retry!
// How to re-run this whole block?
});
I can keep track of the success and failed outcomes. However, is it possible to retry the whole test().then().catch() chain if we fail? And keep retrying until the condition resolves?
If you can switch to async/await syntax, you can use a while loop:
let keepTrying;
do {
try {
await test();
keepTrying = false;
} catch {
keepTrying = true;
}
} while (keepTrying)
doSomething();
You could then abstract the retrying logic into its own function to be reused.
Assuming it's all about resending request to some buggy/bloat-up 3rd party API
If it's production question rather educational one I'd suggest search for 3rd party lib that implementing this on your own.
Say for axios there is nice axios-retry.
Why? Assume you may think there is just one case when API say returns 502. But actually there are much more cases it'd be better to keep in mind:
differing particular error causes, say once there is Network or DNS Lookup Error there may be no need to repeat request
retry count limitation
increasing delay
something else
Writing such a logic on your own would be real overkill. And trying to use simplest solution may hit you when you don't expect it.
PS also as a bonus you would be able to configure all requests to some specific API with single snippet like it goes for axios' custom instances(and I believe there should other plugins for alternative libraries)
You could put the whole thing into a function that recursively calls itself if the catch block is entered:
function tryTest() {
return test().then(function(result) {
// Success: Do something.
doSomething();
}).catch(function(error) {
// error handling
// make sure to return here,
// so that the initial call of tryTest can know when the whole operation was successful
return tryTest();
});
}
tryTest()
.then(() => {
console.log('Finished successfully');
});
If your doSomething can take the result argument, and if tryTest doesn't take any arguments, you can simplify the above to:
function tryTest() {
return test()
.then(doSomething)
.catch(tryTest);
}
tryTest()
.then(() => {
console.log('Finished successfully');
});
You can put it in a function.
function dbug() {
test().then(function(result){
// Success: Do something.
doSomething();
}).catch(function(error){
// Error: Handle the error, retry!
dbug()
});
}

Sequelize findOrCreate() -- .catch() block executed after spread() during no error

My error is similar to this post:
Using sequelize.js as an ORM handler.
queryCondition variable value: {where: {$or: [{username:user.username},{email:user.email}]},defaults:user}
Problem: After successfully saving a user instance to the database, the spread() is called as recommended after invoking findOrCreate(). The function block in spread() is invoked, then immediately after the .catch() block is invoked. No clue why this is happening. Can someone please help?
model.User.findOrCreate(queryCondition).spread(function(user, created){
callback && callback(user, created);
}).catch(function(error){
callback && callback(null, null, error);
});
Found the answer:
Sequelize uses Bluebird.js as it's promise library (check out the package.json file). The documentation explains the spread() method, which is recommended to use in sequelize 3.0 (see post). A section in this document states that spread() invokes all().then(..) under the covers. Therefore, the following change solved my problem using Node.js:
model.User.findOrCreate(queryCondition)
.all().then(function(result, isCreated){
callback && callback(null, result, isCreated);
},
function(error) {
callback && callback(error);
});
Properly resolved promises do not fall into the error block, and actual database errors are caught in the error block. Finally, for those who assumed the error was due to the callback arguments, note that I simply reordered the callback arguments given num8er's suggestion below. :) Hope this helps someone else.
If it's invoking .catch block so it seems to have some issue.
Try to debug it and see the reason:
model.User.findOrCreate(queryCondition).spread(function(user, created){
callback && callback(user, created);
}).catch(function(error){
console.error(queryCondition, error); // add this and check the output
callback && callback(null, null, error);
});
also I saw that Your queryCondition variable is also ok.
{
where:{$or: [{username:user.username},{email:user.email}]},
defaults:user
}
so let's try this annotation:
{
where:{$or: [{username: {$eq: user.username}},{email: {$eq: user.email}}]},
defaults:user
}
read this: http://docs.sequelizejs.com/en/latest/docs/querying/#where
and if with another annotation it will not work properly so I can recommend You to check Your table columns for null, not null fields and compare it with user object to see if there is missing field in user object.
after reading Bergi's comment I'll also recommend You to try to do it like this:
model.User
.findOrCreate(queryCondition)
.then(
function(result, isCreated){
callback && callback(result, isCreated);
},
function(error) {
callback && callback(null, null, error);
});
In case of spread method I think it does not throw exception to be catchable, so in this case:
model.User
.findOrCreate(queryCondition)
.spread(function(result, isCreated){
if(!result) {
return callback && callback('Cannot create user');
}
callback && callback(null, result, isCreated);
});
P.S. Usually in most of packages it's convention to return error as first argument of callback. So I can only guess that problem happens not in Your code example, it happens somewhere outside that waits for callback.
So try to modify callback like this:
callback(user, created); => callback(null, user, created);
callback(null, null, error); => callback(error);

Utilize console logging in native javascript promise chain

I have a native javascript promise chain that looks a little like this:
function chain() {
promiseFunction1().then(function(data) {
console.log("some message");
return promiseFunction2();
}).then(function(data) {
console.log("some message");
return promiseFunction3();
}).then(function(data) {
console.log("some message");
return promiseFunction4();
}).catch(function(error) {
console.error(error.stack);
});
}
the promise functions would look a little like this:
function promiseFunction() {
return new Promise(function(resolve,reject) {
someCallbackfunction(arg, function(err, data){
if (err) {
return reject(err);
}
console.log("some message");
return resolve(data);
});
});
}
My code seems to resolve fine from what I can tell (no errors and I can tell from terminal feedback that the operations I needed started running) but no matter what I seem to try I cannot for the life of me seem to get any form of console logging.
1) Why are these statements not printing like I expect them to?
2) How can I go about getting back my verbose output?
It turned out that in the end the problem was external.
Somewhere in my promise chain I called an external library with a callback function but the library never responded causing my chain to wait forever.
If you experience something similar I encourage you to double check all of the functions in the chain for a similar occurrence.
A quick way to debug this could be to place a timeout in each promise function in the chain that resolves it after x amount of time, that way you can at least get your logging results without having to stumble in the dark forever.

In JavaScript Promises are the reject handler and catch method alternatives [duplicate]

I had a look at the bluebird promise FAQ, in which it mentions that .then(success, fail) is an antipattern. I don't quite understand its explanation as for the try and catch.
What's wrong with the following?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
It seems that the example is suggesting the following to be the correct way.
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
What's the difference?
What's the difference?
The .then() call will return a promise that will be rejected in case the callback throws an error. This means, when your success logger fails, the error would be passed to the following .catch() callback, but not to the fail callback that goes alongside success.
Here's a control flow diagram:
To express it in synchronous code:
// some_promise_call().then(logger.log, logger.log)
then: {
try {
var results = some_call();
} catch(e) {
logger.log(e);
break then;
} // else
logger.log(results);
}
The second log (which is like the first argument to .then()) will only be executed in the case that no exception happened. The labelled block and the break statement feel a bit odd, this is actually what python has try-except-else for (recommended reading!).
// some_promise_call().then(logger.log).catch(logger.log)
try {
var results = some_call();
logger.log(results);
} catch(e) {
logger.log(e);
}
The catch logger will also handle exceptions from the success logger call.
So much for the difference.
I don't quite understand its explanation as for the try and catch
The argument is that usually, you want to catch errors in every step of the processing and that you shouldn't use it in chains. The expectation is that you only have one final handler which handles all errors - while, when you use the "antipattern", errors in some of the then-callbacks are not handled.
However, this pattern is actually very useful: When you want to handle errors that happened in exactly this step, and you want to do something entirely different when no error happened - i.e. when the error is unrecoverable. Be aware that this is branching your control flow. Of course, this is sometimes desired.
What's wrong with the following?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
That you had to repeat your callback. You rather want
some_promise_call()
.catch(function(e) {
return e; // it's OK, we'll just log it
})
.done(function(res) {
logger.log(res);
});
You also might consider using .finally() for this.
The two aren't quite identical. The difference is that the first example won't catch an exception that's thrown in your success handler. So if your method should only ever return resolved promises, as is often the case, you need a trailing catch handler (or yet another then with an empty success parameter). Sure, it may be that your then handler doesn't do anything that might potentially fail, in which case using one 2-parameter then could be fine.
But I believe the point of the text you linked to is that then is mostly useful versus callbacks in its ability to chain a bunch of asynchronous steps, and when you actually do this, the 2-parameter form of then subtly doesn't behave quite as expected, for the above reason. It's particularly counterintuitive when used mid-chain.
As someone who's done a lot of complex async stuff and bumped into corners like this more than I care to admit, I really recommend avoiding this anti-pattern and going with the separate handler approach.
By looking at advantages and disadvantages of both we can make a calculated guess as to which is appropriate for the situation.
These are the two main approaches to implementing promises. Both have it's pluses and minus
Catch Approach
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
Advantages
All errors are handled by one catch block.
Even catches any exception in the then block.
Chaining of multiple success callbacks
Disadvantages
In case of chaining it becomes difficult to show different error messages.
Success/Error Approach
some_promise_call()
.then(function success(res) { logger.log(res) },
function error(err) { logger.log(err) })
Advantages
You get fine grained error control.
You can have common error handling function for various categories of errors like db error, 500 error etc.
Disavantages
You will still need another catch if you wish to handler errors thrown by the success callback
Simple explain:
In ES2018
When the catch method is called with argument onRejected, the
following steps are taken:
Let promise be the this value.
Return ? Invoke(promise, "then", « undefined, onRejected »).
that means:
promise.then(f1).catch(f2)
equals
promise.then(f1).then(undefiend, f2)
Using .then().catch() lets you enable Promise Chaining which is required to fulfil a workflow. You may need to read some information from database then you want to pass it to an async API then you want to manipulate the response. You may want to push the response back into the database. Handling all these workflows with your concept is doable but very hard to manage. The better solution will be then().then().then().then().catch() which receives all errors in just once catch and lets you keep the maintainability of the code.
Using then() and catch() helps chain success and failure handler on the promise.catch() works on promise returned by then(). It handles,
If promise was rejected. See #3 in the picture
If error occurred in success handler of then(), between line numbers 4 to 7 below. See #2.a in the picture
(Failure callback on then() does not handle this.)
If error occurred in failure handler of then(), line number 8 below. See #3.b in the picture.
1. let promiseRef: Promise = this. aTimetakingTask (false);
2. promiseRef
3. .then(
4. (result) => {
5. /* successfully, resolved promise.
6. Work on data here */
7. },
8. (error) => console.log(error)
9. )
10. .catch( (e) => {
11. /* successfully, resolved promise.
12. Work on data here */
13. });
Note: Many times, failure handler might not be defined if catch() is
written already.
EDIT: reject() result in invoking catch() only if the error
handler in then() is not defined. Notice #3 in the picture to
the catch(). It is invoked when handler in line# 8 and 9 are not
defined.
It makes sense because promise returned by then() does not have an error if a callback is taking care of it.
Instead of words, good example. Following code (if first promise resolved):
Promise.resolve()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
is identical to:
Promise.resolve()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)
But with rejected first promise, this is not identical:
Promise.reject()
.then
(
() => { throw new Error('Error occurs'); },
err => console.log('This error is caught:', err)
);
Promise.reject()
.catch
(
err => console.log('This error is caught:', err)
)
.then
(
() => { throw new Error('Error occurs'); }
)

Parse .then method and chaining | Syntax eludes me | TypeError error (ParseCDN)

Previous post: Parse .then method and chaining | Syntax eludes me
My original question was well answered by Nath. However I'm currently experiencing a TypeError which I am yet unable to resolve.
TypeError message:
TypeError: e is undefined
...arse.Object");return{__type:"Pointer",className:this.className,obj
My current code (updated 2014-08-14 18:44):
function harness(){
try{
console.log("harness function");
Parse.initialize("*key1*", "*key2*"); //Note: I do have the keys set properly
var query = new Parse.Query("Users");
var userEmail = app.getValue("txtEmail");
console.log("userEmail: "+userEmail);
//Note: Using Application Craft hence the use of 'app.getValue' and other custom JS functions
query.equalTo("email", userEmail); console.log(query);
query.find().then(
function(results) {
console.log("Within the Then!");
console.log(results);
return query.find();
},
function(error){
console.log("Could be an error"+error);
return;
}
);
console.log("END harness function");
}
catch(err){
errorHandler("harness ERROR", err.message);
console.log(err);
}
}
Having read various forum posts I've investigated the stack trace and given the variable 'e' am fairly certain it's the ParseCDN I'm not calling correctly. I suspect my inexperience with returning promises is the source of the issue (tried to follow Nath's advice). The commented code block at the top was one of my variations of a promise to be returned; having read through the Parse API Docs it seemed that .then inherently returned a promise anyway so 'settled' on simply returning my results, and then the queryObject again (per their samples).
The DOM upon error is interesting because it lists find(e) as a method, yet not then(). Not sure if I'm referring to an outdated js library perhaps (don't think so).
If anyone can assist, or potentially expand upon Nath's work so far (copy below) I would greatly appreciate it.
Many thanks
-James
Amended code snippet from Nath
query.find().then(function(result){
doSomethingAsync(); //must return a promise for chaining to work!
}).then(null,function(error){
// an alternative way to handle errors
//handles errors for all chained promises.
})

Categories