|jQuery 3 - Implementing Promises|
|Written by Ian Elliot|
|Monday, 29 May 2017|
Page 2 of 3
A private method is one that is created as a closure when an object is created. This is the standard method for creating a private variable accessible from within an object but not from outside. The only difference is that the variable references a function. For example:
This is a constructor for an object with just one method, myFunction. The important part is the variable called private. This is not part of the object because it isn't declared as a property of the object. so if you try
you will see an error that private doesn't exist. However, as private is in scope when myFunction is declared, it is available to it as a closure. That is:
does display the value of private.
A private method uses the same mechanism with the small difference that the variable references a function.
You can see that it has the same basic structure the only difference is that now the code that calls the private resolve and reject functions is passed to the constructor. The constructor executes this immediately and returns the promise.
The Then Parameter Problem
As delay now returns a promise, it seems obvious that it could be used in a chain (see the previous chapter). However, there is a problem.
If you try:
where getTime is something like:
which shows a timer count in milliseconds, what you discover is that it appears to work, but if you look carefully the getTime functions report times that are only a few milliseconds apart, rather than 1000ms apart.
The reason should be easy to spot. The functions that are being passed to the then function have parameters and this means they are evaluated at once and not passed to the then to be activated at a later time.
The problem is that you cannot pass a parameter to a function that you use in a then.
Notice that when it is called by the promise, the function may be passed any number of parameters depending on the way the promise is settled.
There are a number of solutions to the problem, but none are 100% satisfactory.
The first, and most obvious, is not to use a parameter at all, but this would result in a delay function that gave a fixed time delay and this generally isn't what you want.
The second is to use a technique from functional programming called "currying" to reduce the number of parameters in the function. For example:
In this case we have used the anonymous function to curry the delay function, i.e. we have reduced the number of parameters to zero. If you try this you will find that it works and each of the times is roughly 1000ms apart.
You can take this one-off currying and create a function that will automatically curry delay for you, for example:
You can see that this is the same idea, but now the delay function returns a function that delays for t milliseconds with no parameters. With this version of delay you can use:
The extra parentheses following the first use of delay are not a misprint. The delay function returns a function that delays for t milliseconds and to implement the delay it has to be called.
The need for the double pairs of parentheses is not nice, but there seems to be no way that a function that returns a promise and accepts parameters can be used in the same way outside and inside a then.
The final way of doing the job is to use bind to curry the delay function. The bind function returns another function with a specified context and fixed values for any of its parameters. Using the original delay function we can call it in a then using:
The bind returns a function with the call context set to null and the first parameter set to 1000. The call to bind is reputed to be slow.
Of the solutions, probably the best is to write the function using a parameter and remember to wrap it in an anonymous currying function if you use it in a then:
This is one of the negative features of using promises. You have to remember that a function that returns a promise can have parameters, but you cannot specify these parameters when you use the function in a then unless you use currying or something similar.
The jQuery Deferred only provides all.
Rather than providing lots of different standard promise-composing functions, it is simpler to learn how to write your own that do exactly what you want. Usually the problem is how to handle rejects, and this you can tailor to the situation.
As an example, let's implement a simple version of the race function which returns a promise that resolves when the first of two promises resolve. It is always a good idea to try to implement an idea as simply as possible and then extend it to more realistic examples. It turns out that race is very easy to write:
All that happens is that we return a new promise object that is resolved or rejected when any of the promises provided as arguments resolves or rejects. Notice that we don't do anything to stop the other promises from completing. It is generally difficult to cancel a pending asynchronous operation. Also notice that as a promise is immutable we don't need to worry about later promises settling and trying to set the returned promise to something different.
This can be used to get the first promise to resolve or reject:
In this case you will see a delay of 1000ms.
|Last Updated ( Thursday, 05 May 2022 )|