On Jun 22, 2013, at 6:41 PM, Paul Tiseo wrote:
> So, I usually get stuck at the start: creating promises. Now, most tutorial are unfortunately very vague and missing on tangible examples. Let's take two of the first promises we need: validateEmail() and readTemplate().
>
> For validateEmail(), I am using the validator (
https://npmjs.org/package/validator) library. The call to isEmail() returns an exception, so is this how we promisify things?
>
> var validateEmail = function (email) {
> var d = when.defer();
> try {
> check(email).len(6,320).isEmail();
> d.resolve(email);
> }
> catch(e) {
> d.reject();
> }
> return d.promise;
> }
I've found most of the time it's simpler than you would think, and actually you usually don't need to create a promise and a deferred object yourself.
What you have there is possibly a valid correct way to "promisify" a method, but if you look into the documentation at:
https://github.com/cujojs/when/blob/master/docs/api.md#synchronous-functions you should be able to do it more straightforwardly. Basically if you have a synchronous method that either returns a value or throws, you can promisify it using when/function. With the setup described on that page you should be able to do something as simple as:
fn.call(validateEmail, email)
or promiseValidate = fn.bind(validateEmail)
where:
function validateEmail(email) {
check(email).len(6,320).isEmail();
return email;
}
I imagine the first line in this function call would just throw on an error, and otherwise you get the returned email. Passing this function to fn.call or fn.bind takes care of the "try-catch" code you were writing for you.
Then you would be starting your snippet with:
when.join(promiseValidate(email), … )
In general, "when.js" offers a number of common ways to obtain/combine promises without having to construct defer objects yourself. The only case I believe when I felt some need to add a defer object was in some code for returning a promise on a database object while attempting to connect to it.
> And, for readTemplate, I simply use lift() as in:
>
> var readTemplate = whennode.lift(fs.ReadFile);
>
> to promisify things.
Looks about right, except I think the method is called fs.readFile, lowercase r.
> So, technically, this restify call should print out the POSTed email and the content of the twop template files, correct? Unfortunately, it doesn't.
>
> function signup2(req, res, next) {
> console.log(req.params.email);
> when.join( validateEmail(req.params.email), readTemplate(__dirname + '/templates/basic_email.html'), readTemplate(__dirname + '/templates/basic_email.txt') )
> .then(
> function(values) { console.write(values[0]); console.write(values[1]); console.write(values[2]); }
> );
> return next();
> }
One thing that I found took me a while to realize is that a thrown exception will simply get lost if I don't add a handler to it at some point. For instance in this case your code could be barfing because of the "ReadFile" typo and you wouldn't know it because you haven't added anything to handle the case of a rejected promise, you are only handling the case of a fulfilled promise. Basically:
"Once you are in a promise setting/chain, your code will not be throwing exceptions any more. It will be rejecting promises. And those rejections are silent unless they are listened for."
What promises offer you is a way to handle all the exceptions from all the intermediate steps in one place at the end, if you so choose.
To catch those errors and print a message on them you have two main options, I believe:
1. Pass a second argument to ".then". It would be a function expecting an error object, and it is what would get called if any of your promises along the way was rejected.
2. Chain to ".then" a ".otherwise", with one argument being that same error handler.
So the code in general looks like one of these:
when( ….)
.then(successFunction, errorFunction);
or
when(…)
.then(successFunction)
.otherwise(errorFunction);
These are both discussed in the "main promise API" and "extended promise API" sections here:
https://github.com/cujojs/when/blob/master/docs/api.md#promise
Haris Skiadas