Is there any way to execute callback on both results of Promise object?
For example I want to make some cleanup logic after execution of xhr request. So I need to do something like this:
var cleanUp = function() { something.here(); }
myLib.makeXhr().then(cleanUp,cleanUp);
In jquery Defered for example i can use method always():
myLib.makeXhr().always(function() { something.here(); });
Does Promise support something like this?
No, there is none. It was discussed but the spec is minimal. It doesn't include a bunch of other functionality. It's designed to interoperate well with library promises and to provide simple functionality.
Here is a correct polyfill of that proposal originally made by StefPanner.
Moreover, I disagree with the current now deleted answers adding it themselves because they're all doing it wrong (as an enumerable property - no fun). Even if we ignore what it does to the return values and error state of the returned promise. The intended way to extend native promises is by subclassing them, sadly, no browsers support this yet so we'll have to wait.
Instead of messing with native prototypes, we should use a different pattern:
openDb().then(foo).then(bar).finally(close).then(more);
Is susceptible to us forgetting to call close, even if we open it 100 times in our app, forgetting to close it even once can still be devastating. On the other hand - we can use the disposer pattern which some promise libraries provide built in ourselves:
openDb(function(db){
return foo(db).then(bar);// chain here
}).then(more);
Basically - this pattern means instead of having openDB return a promise - we have it take a function and return a promise, when the function is run, if it returns a promise we wait for that promise to resolve. It looks something like:
function openDb(withDb){
return justOpenWithoutCleanUp().
then(withDb).
then(clean, function(e){ clean(); throw e; }); // note the rethrow
}
Promise object supports 'always'.
For eg:
var oPromise= jQuery.ajax({
url:YOUR_URL
}).always(function(){
YOUR_CLEAN_UP_METHOD();
})
Related
What are the differences between Mozilla's JavaScript docs' Promises (see API page) and jQuery's Promises (see API page)?
Mozilla's promise seems to have only 2 methods: then and catch. jQuery's promise seems to have more methods, including: then, done, and fail. (from here)
How come the JS API on Mozilla doesn't have done()? What if I want to have a done() functionality in JavaScript? What do I do?
Mozilla's javascript promises are based on ES6 standard, whereas jQuery promises were something created before ES6 was released.
Based on my reading of the jQuery docs, ES6 then is equivalent to jQuery done.
There are actually a boatload of promise libraries, but to me the ES6 one is the simplest to understand. You don't need more than "then" and "catch" and it is real easy to chain together into a sequence of operations. Add to that with Promise.all for parallel tasks and 99% of what you need is covered.
return doSomething().then(function(result) {
return doSomethingElse(result);
}).then(function(secondResult) {
return doThirdSomething(secondResult);
}).catch(function(err) {
console.log(err);
}).then(function(finalResult) {
// a then after a catch is like a "finally" or "always"
return finalResult;
});
Some things that jQuery does support that is not in ES6 is some sort of "progress" resolve.
jQuery's deferred API is bloated and predates promise libraries. Once they realised how useful promises were, they added a then (or previosly, pipe) method, however it they failed to get it 100% right.
How come the JS API on Mozilla doesn't have done()?
It's completely unnecessary. All Promises/A+ compatible implementations (which includes ES6) only need a single method: .then(). It's completely universal, you can do everything with it - it's the primitive of promises.
What if I want to have a done() functionality in JavaScript? What do I do?
Well, you could implement it yourself:
Promise.prototype.done = function(cb) { // or function(...cbs) for (let cb of cbs) …
this.then(cb).then(null, function(err) { /* ignore */ });
return this;
};
But as you can see from that, it's not very useful actually. It doesn't chain, and it ignores exceptions, so you should just use then everywhere.
I can speak for why ES6 don't have .done. However, you can still have something that's akin to .done.
yourPromiseObject.then(successHandler).catch(failureHandler).then(doneHandler);
The first then handles a success response, but will not be called with the yourPromiseObject's function rejects or throw exception. The second catch is critical in "resolving" any exceptions/rejection (in short, you tell the promise object to keep going, you know that there's an error). Make sure you return something valid, even something as simple as the failureHandler consist of nothing but a return 0 will work. The final .then is now guaranteed to be called, so that's your .done
Assuming I have a function which calls two dependend async functions
function targetFn() {
asyncFn1();
asyncFn2();
}
This is clearly a defect, since asyncFn2 does not wait for asyncFn1 to be completed. The correct implementation would be:
function targetFn() {
asyncFn1().then(asyncFn2);
}
However, how to test this? Maybe I test it like this:
it("ensures the ordering", function() {
spyOn(window, "asyncFn1").and.callFake(function() {
return $q.reject("irrelevant");
});
spyOn(window, "asyncFn2");
$timeout.flush();
expect(asyncFn2).not.toHaveBeenCalled();
});
This is okay for this simple test case. But what if I have several chained async functions? The test effort would grow exponential; I have to test every possible combination of rejection and resolving for every promise. What if I change a sync function so that it is an async function afterwards? I would introduce a defect behavior in every callee function without any failing tests.
What I really want is an automatic detection of unhandled promises. Going back to the first example:
function targetFn() {
asyncFn1();
asyncFn2();
}
The test system should recognizes that asyncFn1 and asyncFn2 are creating new promises, but that there are no then and catch handler. Also the second example should of course fail:
function targetFn() {
asyncFn1().then(asyncFn2);
}
Because the then introduces a new promise which is not handled, since it is not returned.
I would like to write a test like:
it("does not introduce unhandled promises", function() {
expect(targetFn).doesNotIntroduceUnhandledPromises();
});
And it checks if every promise created during the execution of targetFn has either an "endpoint" like a finally or is chained to the promises returned by the targetFn.
Do you have any idea how to achive this? Or even a better solution for this?
Thanks
Timo
This is clearly a defect, since asyncFn2 does not wait for asyncFn1 to be completed. The correct implementation would be:
No it's not, it's pretty common to want to perform two operations in parallel, or even downright ignore one's result:
function loadNewData() {
reportDataLoadedToGoogleAnalytics();
return dataService.loadNewData("someParameter");
}
Your issue though, is that your promises aren't being returned. As a rule of thumb whenever a method performs something async with promises, it should return a promise. That would effectively eliminate your problem of testing interesting promises (return them in mocha)
What I really want is an automatic detection of unhandled promises.
That's actually quite possible, you can either use a powerful library like bluebird and swap out $q and use its built in facilities or decorate $q yourself. However when I tried to do these decorations it ended up so hacky I begged satan to take my soul (had to do new Error().stack and grep it for a function name).
I have a function,
Edit1 - Updated function with real one because the previous one was simplified synchronous function and the code would have worked as correctly pointed by #AlexMA in the comments
'returnSuccessOrFailure': function () {
return driver.findElement(wd.By.css('div#button')).then(function (button) {
return button.getAttribute('class').then(function (status) {
return status;
});
});
}
In my node.js test, my assertion is failing because the assert is called before returnSuccessOrFailure finishes execution.
var value = returnSuccessOrFailure();
assert.equal(value,'success', 'Looks like something failed');
If I implement a promise in returnSuccessOrFailure and chain my assert then that works. My question is do I have to implement promises all the time for such situations to block the execution? I am new to Javascript and the async nature of it and any insight when to use promises and when not to would be useful.
you don't have to "implement a promise" in, just return the one you already have:
returnSuccessOrFailure': function () {
return driver.findElement(wd.By.css('div#button')).then(function (button) {
...
but then, yes, you do still need to put your assert in a done handler
returnSuccessOrFailure().done(function(value) {
assert.equal(value,'success', 'Looks like something failed');
}
Chaining you asserts will not only make it work but will also make for more readable code. Knowing what happens in what order can be useful when going back to refactor. Not only that but the structure of callbacks/promises also allow for easily written timer tests.
Also, since your test needs to have the current state of execution, it is more than likely that writing tests with asserts in callbacks is what you will need anyway.
My question is do I have to implement promises all the time for such situations to block the execution?
Notice that promises don't block the execution. They defer the execution of code that depends on the result, notice that you're still chaining callbacks on them.
I am new to Javascript and the async nature of it and any insight when to use promises and when not to would be useful.
Promises are useful wherever you have some code that might run asynchronously and needs to pass back an asynchronous result. Otherwise you would need to use callbacks, which are way more ugly than promises.
This is part of code contracts and representing preconditions (what holds before you execute), postconditions (what holds after you execute), and object invariants (what can not change). JavaScript does not have native support for this, but you can use third party libraries (Cerny.js, ecmaDebug, jsContract, or jscategory)
I think it depends on your coding style, is it EAFP(Easier to ask for forgiveness than permission) or LBYL(Look before you leap). Both are viable! In most compiled languages you would use LBYL. However in Python for example you would use EAFP.
Generally if you know you will fail you want to fail fast. If you like to use assertions to ensure code fails fast it is up to you.
I have a number of async tasks that need to be completed, so I'm using promises.
I need to detect when each one of the promises has been executed (both resolved and rejected). I must not continue execution until that point.
I was using something like this:
$.when(promise1, promise2, ...).always();
But this code is wrong, because the when method has lazy evaluation, and it returns as soon as one of the promises fails. So the always callback also runs as soon as one of the promises fail.
I was thinking in coding a workaround, but this use case is so common that maybe somebody has done it already, or maybe there's even a way of doing this using just jQuery (if not, it would be nice to add a Promise.whenNonLazy or a Promise.when(promise1, promise2, ..., false) in the future.
Is this possible?
More sophisticated promise libraries have an allSettled() function like Q or Promise.settle like Bluebird.
In jQuery, you could implement such a function yourself as well and extend the $ namespace with it, but that will only be necessary if you need it often and performance-optimized.
A simpler solution would be to create a new promise for each of the ones you are waiting for, and fulfilling them even when the underlying one is rejected. Then you can use $.when() on them without problems. In short:
// using Underscore's .invoke() method:
$.when.apply(null, _.invoke(promises, "then", null, $.when)).done(…)
More stable:
$.when.apply($, $.map(promises, function(p) {
return p.then(null, function() {
return $.Deferred().resolveWith(this, arguments);
});
})).then(…);
You might change the then callbacks a bit to distinguish between fulfilled and rejected results in the final done.
Smithy,
First let's assume your promises are in an array.
var promises = [....];
What you appear to want is .when() applied to some transform of these promises, such that any rejected promise is converted to resolved, whilst being transparent to promises that are already resolved.
The required operation can be written very succinctly as follows :
$.when.apply(null, $.map(promises, resolvize)).done(...);
//or, if further filtering by .then() is required ...
$.when.apply(null, $.map(promises, resolvize)).then(...);
where resolvize is the transform mechanism.
So what should resolvize(), look like? Let's exploit the characteristics of .then() to make the distinction beteween a resolved and a rejected promise, and respond accordingly.
function resolvize(promise) {
//Note: null allows a resolved promise to pass straight through unmolested;
return promise.then(null, function() {
return $.Deferred().resolve.apply(null, arguments).promise();
});
}
untested
With resolvize in some outer scope, it can be made available to be used in a $.when.apply($.map(promises, resolvize)) expression wherever it is needed. This is most likely adequate, without going to the extent of extending jQuery with a new method.
Regardless of how the transform is achieved, you end up with a potential issue; namely knowing for each argument of the .done() callback, whether its corresponding promise was originally resolved or rejected. That's the price you pay for converting rejection to resolution. You may, however, be able to detect the original status from the parameter(s) with which the original promises were resolved/rejected.
That's an interesting property of always - I hadn't expected that behaviour.
I suppose you could use a master, top-level deferred to monitor the states of the main deferreds, which is resolved only once the main deferreds are all either resolved or rejected. Something like:
//set up master deferred, to observe the states of the sub-deferreds
var master_dfd = new $.Deferred;
master_dfd.done(function() { alert('done'); });
//set up sub-deferreds
var dfds = [new $.Deferred, new $.Deferred, new $.Deferred];
var cb = function() {
if (dfds.filter(function(dfd) {
return /resolved|rejected/.test(dfd.state());
}).length == dfds.length)
master_dfd.resolve();
};
dfds.forEach(function(dfd) { dfd.always(cb); });
//resolve or reject sub-deferreds. Master deferred resolves only once
//all are resolved or rejected
dfds[0].resolve();
dfds[1].reject();
dfds[2].resolve();
Fiddle: http://jsfiddle.net/Wtxfy/3/
From what I have understood there are three ways of calling asynchronous code:
Events, e.g. request.on("event", callback);
Callbacks, e.g. fs.open(path, flags, mode, callback);
Promises
I found the node-promise library but I don’t get it.
Could someone explain what promises are all about and why I should use it?
Also, why was it removed from Node.js?
Since this question still has many views (like mine) I wanted to point out that:
node-promise looks rather dead to me (last commit was about 1 year ago) and contains nearly no tests.
The futures module looks very bloated to me and is badly documented (and I think that the naming conventions are just bad)
The best way to go seems to be the q framework, which is both active and well-documented.
Promises in node.js promised to do some work and then had separate callbacks that would be executed for success and failure as well as handling timeouts. Another way to think of promises in node.js was that they were emitters that could emit only two events: success and error.
The cool thing about promises is you can combine them into dependency chains (do Promise C only when Promise A and Promise B complete).
By removing them from the core node.js, it created possibility of building up modules with different implementations of promises that can sit on top of the core. Some of these are node-promise and futures.
A promise is a "thing" which represents the "eventual" results of an operation so to speak. The point to note here is that, it abstracts away the details of when something happens and allows you to focus on what should happen after that something happens. This will result in clean, maintainable code where instead of having a callback inside a callback inside a callback, your code will look somewhat like:
var request = new Promise(function(resolve, reject) {
//do an ajax call here. or a database request or whatever.
//depending on its results, either call resolve(value) or reject(error)
//where value is the thing which the operation's successful execution returns and
//error is the thing which the operation's failure returns.
});
request.then(function successHandler(result) {
//do something with the result
}, function failureHandler(error) {
//handle
});
The promises' spec states that a promise's
then
method should return a new promise that is fulfilled when the given successHandler or the failureHandler callback is finished. This means that you can chain together promises when you have a set of asynchronous tasks that need to be performed and be assured that the sequencing of operations is guaranteed just as if you had used callbacks. So instead of passing a callback inside a callback inside a callback, the code with chained promises looks like:
var doStuff = firstAsyncFunction(url) {
return new Promise(function(resolve, reject) {
$.ajax({
url: url,
success: function(data) {
resolve(data);
},
error: function(err) {
reject(err);
}
});
};
doStuff
.then(secondAsyncFunction) //returns a promise
.then(thirdAsyncFunction); //returns a promise
To know more about promises and why they are super cool, checkout Domenic's blog : http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/
This new tutorial on Promises from the author of PouchDB is probably the best I've seen anywhere. It wisely covers the classic rookie mistakes showing you correct usage patterns and even a few anti-patterns that are still commonly used - even in other tutorials!!
http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
Enjoy!
PS I didn't answer some other parts of this question as they've been well covered by others.
Mike Taulty has a series of videos, each of them less than ten minutes long, describing how the WinJS Promise library works.
These videos are quite informative, and Mike manages to show the power of the Promise API with a few well-chosen code examples.
var twitterUrl = "http://search.twitter.com/search.json?q=windows";
var promise = WinJS.xhr({ url: twitterUrl });
promise = promise.then(
function (xhr) {
},
function (xhr) {
// handle error
});
The treatment of how exceptions are dealt with is particularly good.
In spite of the WinJs references, this is a general interest video series, because the Promise API is broadly similar across its many implementations.
RSVP is a lightweight Promise implementation that passes the Promise/A+ test suite. I quite like the API, because it is similar in style to the WinJS interface.
Update Apr-2014
Incidentally, the WinJS library is now open source.
Another advantage of promises is that error handling and exception throwing and catching is much better than trying to handle that with callbacks.
The bluebird library implements promises and gives you great long stack traces, is very fast, and warns about uncaught errors. It also is faster and uses less memory than the other promise libraries, according to http://bluebirdjs.com/docs/benchmarks.html
What exactly is a Promise ?
A promise is simply an object which represents the result of an async operation. A promise can be in any of the following 3 states :
pending :: This is the initial state, means the promise is neither fulfilled nor rejected.
fulfilled :: This means the promise has been fulfilled, means the value represented by promise is ready to be used.
rejected :: This means the operations failed and hence can't fulfill the promise.
Apart from the states, there are three important entities associated to promises which we really need to understand
executor function :: executor function defines the async operation which needs to be performed and whose result is represented by the promise. It starts execution as soon as the promise object is initialized.
resolve :: resolve is a parameters passed to the executor function , and in case the executor runs successfully then this resolve is called passing the result.
reject :: reject is another parameter passed to the executor function , and it is used when the executor function fails. The failure reason can be passed to the reject.
So whenever we create a promise object, we've to provide Executor, Resolve and Reject.
Reference :: Promises
I've been also looking into promises in node.js recently. To date the when.js seems to be the way to go due to its speed and resource use, but the documentation on q.js gave me a lot better understanding. So use when.js but the q.js docs to understand the subject.
From the q.js readme on github:
If a function cannot return a value or throw an exception without
blocking, it can return a promise instead. A promise is an object that
represents the return value or the thrown exception that the function
may eventually provide. A promise can also be used as a proxy for a
remote object to overcome latency.
Promise object represents the completion or failure of an asynchronous operation.
So in order to implement a promise, you need two parts:-
1.Creating Promise:
The promise constructor accepts a function called an executor that has
2 parameters resolve and reject.
function example(){
return new Promise (function(resolve , reject){ //return promise object
if(success){
resolve('success'); //onFullfiled
}else{
reject('error'); //onRejected
}
})
}
2.Handling Promise:
Promise object has 3 methods to handle promise objects:-
1.Promise.prototype.catch(onRejected)
2.Promise.prototype.then(onFullfiled)
3.Promise.prototype.finally(onFullfiled,onRejected)
example.then((data) =>{
//handles resolved data
console.log(data); //prints success
}).catch((err) => {
//handles rejected error
console.log(err); //prints error
})