I have been working with Promises in Javascript lately but I have difficulty trying to understand what exactly happens here.
A Google Maps script url is being set with a callback of initMap. So when Google Maps finishes loading this callback will fire.
In turn it calls resolveFunc(). resolvefunc() is set within the promise but I don't get this part:
resolveFunc = resolve;
What is the use of setting it equal to the resolve function?
<script>
var resolveFunc = null;
var promise = new Promise(function(resolve, reject) {
resolveFunc = resolve;
});
promise.then(function() {
console.log('loaded');
});
function initMap() {
resolveFunc();
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?callback=initMap" async defer></script>
The only reason I can see for this construction is that you want to be able to access a Promise that resolves when the google maps api is loaded.
A new promise object is created.
The resolve function of that promise is assigned out of scope in to a window variable resolveFunc
A .then is assigned to the promise that issues a console log when the promise resolves.
The assigned resolve function is called when the initMap function is run by the external gmaps script.
The console.log inside the .then will fire.
I can't see any need for this that running code inside the initMap without the promise construction could also achieve.
I've never seen this construction before.
I can only think of one reason for it: to allow some sort of modularization. The loading of the Google Maps URL will trigger the resolution of that promise. In the meantime, other modules may have attached themselves with .then to this promise, to be run when this script has been loaded.
That global promise variable is really ugly, but it would serve for this purpose.
Note: I mean 'module' in its generic sense: some reasonably independent, cohesive chunk of code.
The idea behind this pattern is that the script, that is loaded with:
src="https://maps.googleapis.com/maps/api/js?callback=initMap"
..., should be able to resolve the promise. For that the script needs to call the resolve function that the promise constructor provides. But since resolve is local to that constructor, the authors have used a solution where they assign that function to a global variable, which will be available to the loaded script.
That script will certainly look at the callback argument present in the url, and extract the value following it. It will be assigned to some variable, let's say callback, and then they will trigger the resolution with:
window[callback]();
which will be synonym for resolveFunc, which in turn is synonym for resolve.
That script could not have done that with a call to resolve:
resolve();
... as that would be an unknown variable.
This approach is known as Deferred pattern which was notably implemented in jQuery. It is prone to be antipattern but is possibly justified here because it's a reasonable way to move from Google Maps API callback to a promise.
promise resolution is deferred until resolveFunc callback is called. promise is global and can be used inside the application. In case it's not used, this can be considered antipattern for the reasons mentioned above:
It is easy to fall into this when you don't really understand promises and think of them as glorified event emitters or callback utility.
It could be just:
<script>
function initMap() {
console.log('loaded');
}
</script>
Related
I have a single page app in angular. There is a global available state available through a context service.
This context service has a get and set method. The get method is a promise since the context is not yet set up once the page is loaded but is gotten through an API.
Once the context is set-up the promise is resolved and I can access my context through the get method.
However how can I deal with the set method. It is possible to change the context with the set method. But since the promise is already resolved the get method will return the old context.
Is it possible to 'substitute' the data the promise returns on a then call after it has been resolved?
Thanks!
The get method is a promise...
That doesn't make much sense. I'm assuming it returns a promise.
However how can I deal with the set method. It is possible to change the context with the set method. But since the promise is allready resolved the get method will return the old context.
Code shouldn't keep and reuse the old promise like that. E.g., you're suggesting:
var p = object.getThePromise();
p.then(function(value) {
// ...use the value...
});
// later - this is the bit that's wrong
p.then(function(value) {
// ...use the value...
});
It shouldn't do that. It should go back to getThePromise if it wants the value again later (if it wants a new value).
Is it possible to 'substitute' the data the promise returns on a then call after it has been resolved?
No. An important part of the promise contract is that a promise is only ever settled once, and the settled value does not change.
It's hard to say without seeing your API, but if the API gives the impression you can call the "get" and then reuse the resulting promise, it would be best to change the API to make it no longer give that impression. But again, without API specifics, it's hard to say whether that's the case or suggest a change.
In the OpenUI5 code-base I came across this snippet:
// Wait until everything is rendered (parent height!) before reading/updating sizes.
// Use a promise to make sure
// to be executed before timeouts may be executed.
Promise.resolve().then(this._updateTableSizes.bind(this, true));
It looks like the native Promise function is being used, with no argument being passed to it's resolve function which takes an:
Argument to be resolved by this Promise. Can also be a Promise or a
thenable to resolve.
So, since it looks like the promise would simply immediately resolve and invoke then's callback, perhaps the intent is similar to:
var self = this;
setTimeout(function() {
self._updateTableSizes.bind(self, true)
}, 0);
...basically, freeing the JavaScript run-time event-loop to finish other things (like rendering) and then come right back to the callback?
My question is:
Is this a common pattern? Best-practice? Are there any advantages/disadvantages to either approach?
Yes, Promise.resolve() does immediately fulfill with the undefined value that you implicitly passed in. The callback is still executed asynchronously - quite like in the setTimeout snippet you posted.
However, as the comment in the code explains, the intent is not just to execute the callback asynchronously:
Use a promise to make sure to be executed before timeouts may be executed.
Promise callbacks do run before timeouts or other events, and these subtle timing differences are sometimes important. Given that choice of the task loop is usually not important, No this is not a common pattern; but it is a valid pattern that does exactly what you need when you need it.
I noticed the technique in this polyfill: https://github.com/wicg/inert (with comment)
const newButton = document.createElement('button');
const inertContainer = document.querySelector('[inert]');
inertContainer.appendChild(newButton);
// Wait for the next microtask to allow mutation observers to react to the DOM change
Promise.resolve().then(() => {
expect(isUnfocusable(newButton)).to.equal(true);
});
I have a viewmodel for a knockoutjs component. In the viewmodel, there is a function init() that executes for several minutes. Because of this, the UI of the component on the browser freezes until the init() finishes its execution.
function myViewModel(){
self = this;
self.x = ko.observable(0);
self.y = ko.observableArray([]);
self.z = ko.observable({});
self.init = function(){
//Need to use JQuery here
//loading stuff from DB via JQuery ajax
//assign retrieved data to x and y and z
}
}
Is there a way to run init() in the background?
I looked at the possibility of Worker, which runs in the background, but Worker needs to use JQuery. If I pass JQuery (and several other JSON objects) to worker via postMessage, like this: worker.postMessage($), then I get the error:
Failed to execute 'postMessage' on 'Worker': An object could not be cloned.
Any idea how to make init() run in the background to avoid frozen UI?
I tried timeout, like below, but UI still freezes:
self.executeAsync = function(func) {
setTimeout(func, 0);
};
self.executeAsync(self.init);
You can use promises.
As for the comments, your problem is that you know how to use all the ajax promises, but you don't know how to implement your own promise.
As you're using jQuery, let's do it with this library. It's only 3 steps
create a deferred object like this: var deferred = $.Deferred();
return a promise from this deferred, so that you can use .then to include the callbacks when the promise is resolve or rejected. For example: return deferred.promise(); or, if you're returning and object, you can return the promise as a member of that object, to check for completion: return { ..., promise = deferred.promise()};
When your code succeeds or fails, resolve or reject your promise, like this: deferred.resolve(); or deferred.reject();
In your case, create a deferred at the beginning of init(), and when all the jQuery ajax are completed, resolve the promise, or reject it, if something goes wrong.
Some notes on Deferred functionality:
If you resolve (or reject) your deferred passing an object, you'll receive that object as a parameter for your callback
You can return an object wrapped in a promise. For example, if your init() returns an object (for example an object implementing an API), you can return that object wrapped in a promise like this: return deferred.promise(retVal);
The implementation of jQuery promises is not Promises/A+ compatible until version 3.0. That has to do with chaining and exception propagation in callback chains. It will not affect you for this case. In the meantime, you can use other promises libraries like Q, or rsvp, which are Promises/A+ compatible, and implement more functionalities.
You can use deferred.notify to signal progress. Then you can specify a progress callback
Documentation for jQuery's Deferred object.
Pseudo code:
init: function() {
var deferred = $.Deferred();
// run your stuff, for example with setTimeout() or setInterval()
// so that the code follows running on the same line
// eventually, your stuff will resolve or reject the deferred/promise
return deferrer.promise();
}
Then you can use callbacks with your init, like usual: init().then(...);
As you don't explain what your init function does, it's not clear if you have to update some observables, or show some controls or whatever when the promise is resolved. That's up to you.
NOTE: I'm afraid you can be doing something wrong if you manipulate DOM objects with jQuery: when using knockout, all the DOM manipulation should be solved with ko bindings. Mixing up both ways of DOM manipulation can soon become cumbersome
You can import jQuery to the Worker script with importScripts().
At the top of your Worker script, just put importScripts('path/to/jQuery') and you'll have access to jQuery. The importScripts function is a global function in the WorkerGlobalScope interface, so all your workers should have access to it.
I know how to create a promise in Kris Kowal's q with var defer = Q.defer();, calling defer.resolve(); and/or defer.reject() and return defer.promise. But reading the docs, it seem's there is an alternative way to create a promise...
From the docs:
Q.Promise(resolver)
Synchronously calls resolver(resolve, reject, notify) and
returns a promise whose state is controlled by the functions passed to
resolver. This is an alternative promise-creation API that has the
same power as the deferred concept, but without introducing another
conceptual entity.
If resolver throws an exception, the returned promise will be rejected
with that thrown exception as the rejection reason.
This is, what I've tried:
function () {
return Q.Promise(function (resolve, reject) {
(...do something...)
resolve(5); // or: reject(error);
});
}
But this doesn't work as expected!
Can someone give an example, how to use Q.Promise?
UPDATE:
Thanks for downvoting! I asked for an usage example, therefore a simple "you use it in a correct way" is more helpful! Btw: it fails silently and yes, I attached an error handler!
The reason, why the function is unnamed, is that I use it together with map and reduce to create a delayed chain of promises, but it seems, the resolver functions are never called... Therefore I asked for a (again) usage example...
Looking at your 2 examples, I'm guessing you are doing this:
var q = require('q');
Therefore Q.Promise won't work, but rather q.Promise will.
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
})