Working with promises, doing a save - javascript

I have the following cloud function returning immediately, with promise full-filled but without doing its job. Can any one see why?
function myFunction(newValArray)
{
console.log("Entered myFunction.");
var query,classPromise;
query = new Parse.Query("myClass");
classPromise = (query.find().then
(function(result) {
result[0].set("myField", result[0].get("myField")+1);
result[0].save(null,{}).then
(function() {
console.log("1)newValArray:"+newValArray.length.toString());
newValArray.push(result[0].get("myField"));
console.log("2)newValArray:"+newValArray.length.toString());
return Parse.Promise.as();
});
}));
return Parse.Promise.when(classPromise);
}
If I then use this code for :
myFunction(newLTR).then
(function() {
console.log("myFunction FULL-FILLED.");
}
I can see the messages "Entered myFunction." and "myFunction FULL-FILLED." in the logs.
But I never see "1)newValArray:..." neither do I see "2)newValArray:..."
I have also checked that the passed parameter has not been processed as expected.
If I replace myFunction with the following version, it doesn't make any difference:
function myFunction(newValArray)
{
console.log("Entered myFunction.");
var query,classPromise;
query = new Parse.Query("Configuration");
classPromise = (query.find().then
(function(result) {
result[0].set("myField", result[0].get("myField")+1);
result[0].save(null,{
success:function(configRcd) {
console.log("1)newValArray:"+newValArray.length.toString());
newValArray.push(configRcd.get("myField"));
console.log("2)newValArray:"+newValArray.length.toString());
return Parse.Promise.as();
},
error:function(error) {
console.log("Something went wrong in incrementLastTouchReference.");
}});
}));
return Parse.Promise.when(classPromise);
}

That's a terrible way to write your promises. The whole reason you want to use promises in the first place, is so you can chain callbacks. In your example it's the worst of both worlds, the complexity of promises but you're still nesting.
The second issue is that you really need to place a final error handler. Any errors emitted right now might just disappear. always end with a catch.
I rewrote your first function to correctly do promises, but I can't guarantee if there's not something else wrong. Hopefully it helps you along your way:
function myFunction(newValArray)
{
console.log("Entered myFunction.");
var query,classPromise;
query = new Parse.Query("myClass");
classPromise = query.find()
.then(function(result) {
result[0].set("myField", result[0].get("myField")+1);
return result[0].save(null,{});
}).then(function() {
console.log("1)newValArray:" + newValArray.length.toString());
newValArray.push(result[0].get("myField"));
console.log("2)newValArray:"+newValArray.length.toString());
return Parse.Promise.as();
}).then(function(result) {
// I added this third then clause. You were returning
// Parse.Promise.as() so presumably you wanted to do something
// with that. Before this then clause it got discarded, with my
// change the result of Parse.Promise.as() is thrown in the
// 'result' argument in this function.
}).catch(function(err) {
// If an error is thrown in any part of the change, it will
// bubble to this final catch statement.
// Do something with err! Log it or whatever ;)
})
return Parse.Promise.when(classPromise);
}

Related

Promise function do I need use return?

I'm trying to learn pomise and I used code which I found in Internet... I don't understand everything. It looks for me very nasty but it works...
I initialized promise
function initialize(city) {
var options = {
url: 'https://api.weatherbit.io/v2.0//forecast/',
headers: {
'User-Agent': 'request'
}
};
return new Promise(function(resolve, reject) {
request.get(options, function(err, resp, body) {
if (err) {
reject(err);
} else {
resolve(JSON.parse(body));
}
})
})
}
I don't understand why I need to put return after initializePromise. Is it possible to refactor the code without return?
var initializePromise = initialize("Berlin");
return initializePromise.then(function(result) {
weather = result;
var rain = result["data"][0]["precip"];
console.log(rain);
}, function(err) {
console.log(err);
})
This all depends upon what you want to do. If you wrote this version, which is slightly altered from your original but functionally the same:
function f1(city) {
return initialize(city).then(function(result) {
const weather = result
const rain = result["data"][0]["precip"];
console.log(rain)
}, function(err) {
console.log(err)
})
}
then when you call
f1('Berlin')
you would request the Berlin result from the server, When the server responds, you would either pass to console.log the error received from the request or turn the returned body into a JS object, extract the appropriate precip property from it, and log that to the console. The resulting Promise value returned from f1 is useless, and the weather variable is unused and unusable.
If you want to log that precipitation, but still keep a useful return value, you can write:
function f2(city) {
return initialize(city).then(function(result) {
const weather = result
const rain = result["data"][0]["precip"];
console.log(rain)
return weather // *** NOTE new line here ***
}, function(err) {
console.log(err)
})
}
This time calling with Berlin (and ignoring the error case from now on), you would log the precipitation returned, but also return a Promise for the whole Berlin weather node. That means you can still do this:
f2('Berlin')
to log Berlin's first precipitation value, but that now returns a useful value, so you could do
f2('Berlin').then(console.log)
to do that same logging, and then log the entire Berlin result.
Or you could do
f2('Berlin').then(function(weather) {
// do something useful with `weather` here.
}, errorHandler)
But now note the cleanup that is available. First of all the rain variable in f2 is only used on the next line, and the weather one is simply a reference to the original result argument. So we can simplify it this way:
function f3(city) {
return initialize(city).then(function(result) {
console.log(result["data"][0]["precip"])
return result
}, function(err) {
console.log(err)
})
}
This does the same thing more simply. But now there is a much more important simplification. It's quite possible that we don't need this function at all! If we have an error handler of some sort (even if it's just console.err), and we already have a function that does most of the weather handling we want, then instead of
f3('Berlin').then(function(weather) {
// do something useful with `weather` here.
}, errorHandler)
we can add the logging line from f3 into this first callbak, and get the same result by calling directly to initialize:
initialize('Berlin').then(function(weather) {
console.log(weather["data"][0]["precip"])
// do something useful with `weather` here.
}, errorHandler)
The reason this works is because initialize returns the result of calling then on the Promise, and then f2 and f3 also return either an altered value or the original one, keeping a Promise chain intact.
I would suggest that if you're in doubt you return something in any of these situations. It makes it much easier to continue working with values.

Avoiding javascript callback and promise hell

I have many asynchronous methods to execute and my program flows can change a lot depending on each method return. The logic below is one example. I could not write it in a easy-to-read way using Promises. How would you write it?
Ps: more complex flows are welcome.
Ps2: is_business is a predefined flag where we say whether we are writing a "business user" or a "person user".
begin transaction
update users
if updated
if is_business
update_business
if not updated
insert business
end if
else
delete business
end if
else
if upsert
insert user
if is_business
insert business
end if
end if
end if
commit transaction
The nice thing about promises is that they make a simple analogy between synchronous code and asynchronous code. To illustrate (using the Q library):
Synchronous:
var thisReturnsAValue = function() {
var result = mySynchronousFunction();
if(result) {
return getOneValue();
} else {
return getAnotherValue();
}
};
try {
var value = thisReturnsAValue();
console.log(value);
} catch(err) {
console.error(err);
}
Asynchronous:
var Q = require('q');
var thisReturnsAPromiseForAValue = function() {
return Q.Promise(function() {
return myAsynchronousFunction().then(function(result) {
if(result) {
// Even getOneValue() would work here, because a non-promise
// value is automatically cast to a pre-resolved promise
return getOneValueAsynchronously();
} else {
return getAnotherValueAsynchronously();
}
});
});
};
thisReturnsAPromiseForAValue().then(function(value) {
console.log(value);
}, function(err) {
console.error(err);
});
You just need to get used to the idea that return values are always accessed as arguments to then-callbacks, and that chaining promises equates to composing function calls (f(g(h(x)))) or otherwise executing functions in sequence (var x2 = h(x); var x3 = g(x2);). That's essentially it! Things get a little tricky when you introduce branches, but you can figure out what to do from these first principles. Because then-callbacks accept promises as return values, you can mutate a value you got asynchronously by returning another promise for an asynchronous operation which resolves to a new value based on the old one, and the parent promise will not resolve until the new one resolves! And, of course, you can return these promises from within if-else branches.
The other really nice thing illustrated in the example above is that promises (at least ones that are compliant with Promises/A+) handle exceptions in an equally analogous way. The first error "raised" bypasses the non-error callbacks and bubbles up to the first available error callback, much like a try-catch block.
For what it's worth, I think trying to mimic this behavior using hand-crafted Node.js-style callbacks and the async library is its own special kind of hell :).
Following these guidelines your code would become (assuming all functions are async and return promises):
beginTransaction().then(function() {
// beginTransaction() has run
return updateUsers(); // resolves the boolean value `updated`
}).then(function(updated) {
// updateUsers() has "returned" `updated`
if(updated) {
if(isBusiness) {
return updateBusiness().then(function(updated) {
if(!updated) {
return insertBusiness();
}
// It's okay if we don't return anything -- it will
// result in a promise which immediately resolves to
// `undefined`, which is a no-op, just like a missing
// else-branch
});
} else {
return deleteBusiness();
}
} else {
if(upsert) {
return insertUser().then(function() {
if(isBusiness) {
return insertBusiness();
}
});
}
}
}).then(function() {
return commitTransaction();
}).done(function() {
console.log('all done!');
}, function(err) {
console.error(err);
});
The solution is a mix of #mooiamaduck answer and #Kevin comment.
Using promises, ES6 generators and co library makes the code much clearer. I found a good example when reading a postgresql node library example (pg). In the example below pool.connect and client.query are asynchronous operations that returns Promises. We can easily add an if/else after geting result and then make more async operations keeping code looking like synchronous.
co(function * () {
var client = yield pool.connect()
try {
yield client.query('BEGIN')
var result = yield client.query('SELECT $1::text as name', ['foo'])
yield client.query('INSERT INTO something(name) VALUES($1)', [result.rows[0].name])
yield client.query('COMMIT')
client.release()
} catch(e) {
// pass truthy value to release to destroy the client
// instead of returning it to the pool
// the pool will create a new client next time
// this will also roll back the transaction within postgres
client.release(true)
}
})

Try and catch around promise

I need to write a function that returns a promise, where first I call a synchronous function A() which returns some result.
Then return a function B(result) where B is a promise which takes in the result of A().
If either function fails I want the same error function C(error) to get called where C is a promise.
What is the best way of writing this. This is what I have but think there is obvious way I am missing
function() {
try {
var result = A();
return B(result)
.catch(function(error) {
return C(error);
});
}
catch(error) {
return C(error);
}
}
It seems wrong combining synchronous try and catch with a promise .catch and also wrong there are two different places I need to call C(error).
A() throws an error rather than returning an error code.
You don't say exactly how A() fails. It could either throw or it could return an error result. I'll show a scheme for both. The key to a mix of sync and async is to always return a promise. This will give you a consistent interface for teh caller no matter how the function succeeds or fails.
If you are only worried about A() throwing an exception and it doesn't return an error code, then you can do this:
function someFunction() {
try {
var result = A();
return B(result);
} catch(err) {
return Promise.reject(err);
}
}
someFunction().then(function(result) {
// code here to process the final result
}).catch(C);
If you also have the case where A() can return an error code, then you can do this:
function someFunction() {
try {
var result = A();
// check for error value
if (result < 0) {
throw result;
}
return B(result);
} catch(err) {
return Promise.resolve(err);
}
}
Note that both of these patterns avoid creating an extra promise if it isn't needed. They only create the extra promise when returning an error that occurred synchronously.
The Bluebird promise library has a helper function for this particular circumstance called Promise.method. The utility of Promise.method() is that it automatically wraps your function in a try/catch handler and if there are any synchronous exceptions thrown, it automatically turns them into returning a rejected promise. You could use it like this:
var someFunction = Promise.method(function() {
var result = A();
// check for error condition
if (result < 0) {
throw result;
}
return B(result);
});
someFunction().then(function(result) {
// code here to process the final result
}).catch(C);
I'm assuming that both A and B can throw errors here. Using the standard API it could look like this:
function() {
return new Promise((resolve, reject) => {
try {
resolve(A());
} catch (error) {
reject(error);
}
})
.then(B)
.catch(C);
}
This will return a promise that's either resolved with the output of B or the output of C, if that provides a fallback. You can also consider handling any errors outside of this function if that makes sense for your use case.
When using Bluebird this should also be possible:
function() {
return Promise.method(A)().then(B).catch(C)
}
I think a good way to do this would be to still use promises for the synchronous function. It keeps it consistent within a function, especially if you want something to respond to the success like a pseudo-promise. But the key is that you'd use an immediately resolved promise. Take a look at this blog post on ES6 Promises.
// an immediately resolved promise
var a = Promise.resolve(A());
assuming you've already created the promise and defined C like so:
var B = new Promise(function(resolve, reject) {
if (a) {
resolve('success'); // fulfilled successfully
}
else {
C('rejected'); // error, rejected
}
})
.then((result) => {console.log('made it!');})
.catch((result) => {C('rejected');});
var C = (err)=>{console.log('error: ' + err); return err;}
this code should do what you want:
a.then((result) => B(result));
^ this last line is the most important, since it uses the output for A to call B

NodeJS Multiple function promises

Let's say I have some code that looks like this:
var doSomething = function(parameter){
//send some data to the other function
return when.promise(function(resolveCallback, rejectCallback) {
var other = doAnotherThing(parameter);
//how do I check and make sure that other has resolved
//go out and get more information after the above resolves and display
});
};
var doAnotherThing = function(paramers){
return when.promise(function(resolveCallback, rejectCallback) {
//go to a url and grab some data, then resolve it
var s = "some data I got from the url";
resolveCallback({
data: s
});
});
};
How do I ensure that var other has completely resolved before finishing and resolving the first doSomething() function? I'm still wrapping my head around Nodes Async characteristic
I really didn't know how else to explain this, so I hope this makes sense! Any help is greatly appreciated
EDIT: In this example, I am deleting things from an external resource, then when that is done, going out the external resource and grabbing a fresh list of the items.
UPDATED CODE
var doSomething = function(parameter){
//send some data to the other function
doAnotherThing(parameter).then(function(){
//now we can go out and retrieve the information
});
};
var doAnotherThing = function(paramers){
return when.promise(function(resolveCallback, rejectCallback) {
//go to a url and grab some data, then resolve it
var s = "some data I got from the url";
resolveCallback({
data: s
});
});
};
The return of doAnotherThing appears to be a promise. You can simply chain a then and put your callback to utilize other. then also already returns a promise. You can return that instead.
// Do stuff
function doSomething(){
return doAnotherThing(parameter).then(function(other){
// Do more stuff
return other
});
}
// Usage
doSomething().then(function(other){
// other
});
Below is how to accomplish what you're trying to do with bluebird.
You can use Promise.resolve() and Promise.reject() within any function to return data in a Promise that can be used directly in your promise chain. Essentially, by returning with these methods wrapping your result data, you can make any function usable within a Promise chain.
var Promise = require('bluebird');
var doSomething = function(parameter) {
// Call our Promise returning function
return doAnotherThing()
.then(function(value) {
// Handle value returned by a successful doAnotherThing call
})
.catch(function(err) {
// if doAnotherThing() had a Promise.reject() in it
// then you would handle whatever is returned by it here
});
}
function doAnotherThing(parameter) {
var s = 'some data I got from the url';
// Return s wrapped in a Promise
return Promise.resolve(s);
}
You can use the async module and its waterfall method to chain the functions together:
var async = require('async');
async.waterfall([
function(parameter, callback) {
doSomething(parameter, function(err, other) {
if (err) throw err;
callback(null, other); // callback with null error and `other` object
});
},
function(other, callback) { // pass `other` into next function in chain
doAnotherThing(other, function(err, result) {
if (err) throw err;
callback(null, result);
})
}
], function(err, result) {
if (err) return next(err);
res.send(result); // send the result when the chain completes
});
Makes it a little easier to wrap your head around the series of promises, in my opinion. See the documentation for explanation.

Javascript Promises confusion

I'm trying to figure out Promises with Parse.
What I want to do is get a lot of jobs, and then perform an update for each job.
var queryJobs = new Parse.Query("Jobs");
queryJobs.find().then(function (results) {
// Loop thorugh all jobs
for (var i = 0; i < results.length; i++) {
var job = results[i];
// Here. I want to run an update on all object and then continue.
}
return ????;
}).then(function () {
status.success("Finish");
}, function () {
status.error("Error");
});
I tried this without luck. The push block is never executed.
var queryJobs = new Parse.Query("Jobs");
queryJobs.find().then(function (results) {
var promises = [];
// Loop thorugh all jobs
for (var i = 0; i < results.length; i++) {
var job = results[i];
promises.push((function () {
// This is never executed.
var promise = new Parse.Promise();
var query = new Parse.Query("Jobs");
query.first({
success: function (object) {
// ... Do something here....
promise.resolve();
},
error: function () {
promise.resolve();
}
});
promise.resolve();
return promise;
}));
}
return Parse.Promise.when(promises);
}).then(function () {
status.success("Finish");
}, function () {
status.error("Error");
});
Thanks in advance
UPDATE
I've changed the code, and I get into the callback, however, the query is not executed.
...
promises.push((function () {
// GET HERE
var promise = new Parse.Promise();
var query = new Parse.Query("Jobs");
query.first({
success: function (object) {
console.log("CALLBACK");
promise.resolve();
},
error: function () {
console.log("CALLBACK");
promise.resolve();
}
});
}()));
return Parse.Promise.when(promises);
Here is how I would set this up:
var failure = new Parse.Promise();
var success = new Parse.Promise();
var queryJobs = new Parse.Query("Jobs");
queryJobs.each
(
function( job )
{
//Do your changes to the job
return job.save().then
(
function( job )
{
return Parse.Promise.as( "job saved" );
},
function( error )
{
failure.reject("There was an error trying to save a job: " + error.message);
return failure;
}
);
}
).then
(
function( results )
{
success.resolve("Successfully updated all the jobs" )
return success;
},
function( error )
{
failure.reject("There was an error trying to query for Jobs: " + error.message);
return failure;
}
).then
(
function( success )
{
response.success( success );
},
function( failure )
{
response.error( failiure );
}
);
This may not work out of the box, but it has a few key features that may help you.
1) I know that one of the perks that is mentioned in the blog post and what not announces promises is that you can get rid of pyramid code, but if you want descriptive error messages, the pyramid code is a necessary evil. My first promise (queryJobs.each in this case) always has two .then()'s. The second one always just does response.error( failure ) and response.success( success ).
2) I create two promises, although you can use just one. I prefer two so it is clear where I'm failing / succeeding. I return these where I reach a dead end/ the finish line.
3) I used query.each instead of query.find. query.find() is limited to 1000 results, which, while it will probably be more than enough for a long time, will eventually cause you to hit your limit, and you'd need to start paginating your results. Using query.each will perform your function on every single object that could be returned by the query. One perk of query.each vs query.find and iterating through the results is that query.each performs it's callback on each object asynchronously, rather than a linear iteration.
4) In this case it would probably be better just to have return job.save() inside of the each block, but I wanted to show how I do the nested promise returns. This is what allows me to have very specific success / error statements. This is important because even if one link in your promise chain fails, you will keep executing the next links. The exception to this is if a promise is rejected and you don't have an error function until your last chain. The error will get passed from link to link until it finds an error function, which is fine, except it limits how much you can customize your error messages.
I'll also note that what you have is probably going to return the same object again and again for that query.first() method, rather than working with the specific job from the first query. Like, you are iterating through your jobs, but instead of doing anything with each job, you're getting the first job and doing something with it again and again. I don't think that's what you actually wanted, but maybe this is meant to be a "learn promises" post rather than something functional.
Anyway, hope I helped a bit. Let me know if you have questions and I'll do my best to answer them.
edit: I know my style varies greatly from others'. I like opening and closing brackets on a new line, for the most part. I actually read in javascript that this can sometimes cause errors. I forget the specific cases, but this is not one of them. But feel free to edit the style back to how you prefer it.
You have to add promises to promises, not functions. You need to call the function so that it returns the promise:
promises.push((function () {
// ...
}()));
// ^^
Furthermore you have to remove the promise.resolve(); call before the return statement. The promise should only be resolved after the query succeeded. As it currently is, the promise is resolved immediately.

Categories