Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What design pattern is jQuery's Deferreds and Promises?

It seems that jQuery's Deferred actually can handle all the methods that a Deferred object and Promise object can do, but it only returns a Promise object to the user so that a subset of methods is given, so that the user cannot resolve or reject -- for what the user not supposed to do.

So Deferred is actually quite clear as a class. What can be confusing is another class Promise and it made things seem more complicated because now there are two classes for this pattern and it may seem confusing.

I wonder

  1. is the above accurate?
  2. is it a design pattern of its own, or is it actually similar to other classical design patterns that actually have this "many methods" are possible (Deferreds) but "only limit a subset of it to give to the user of the class" (Promises) kind of design pattern?
like image 697
nonopolarity Avatar asked Mar 09 '14 16:03

nonopolarity


Video Answer


2 Answers

jQuery’s promises were partially informed by prior art including Q promises and Dojo and Twisted Python deferreds, which in turn were inspired by promises in E. In E and subsequently Q, the promise and the resolver are separate objects based on the Object Capability Programming (OCap) design principle. In Q, promise and resolve are the separate capability-bearing objects, and the “deferred” is just a container for these capabilities. In the ES6 Promise design, the deferred exists but is absent from the interface to eliminate confusion—instead, the promise constructor takes a callback to which resolve is sent as an argument.

E was designed for object oriented security and robust composition of agents in multiple processes. Promises are an important primitive for ensuring all of E’s goals. The object capability paradigm is an alternative to the access control list paradigm. Instead of user-oriented authorities, capabilities are broken down into individual objects. Granting authority is as simple as giving an agent access to an object that bears a capability, and OCap depends on having an environment where it is possible to guarantee that capabilities can be obtained only by explicit and deliberate interaction with other objects. Revoking an authority is also possible with object membranes created using weak maps (to ensure that memory does not leak) and proxies (to create boundaries where cross-membrane references are always wrapped and can be later broken).

Observation and notification are separate capabilities. It is possible to give some agents the authority to observe the resolution of a promise, and give other agents the ability to resolve a promise. It is important in a secure system that the communication channel is uni-directional. One resolver can communicate one value to all observers, but no observer or resolver should be able to otherwise interfere with the invariants of any other agent.

Promises are a variant of the Gamma et Al Observer pattern or the Publisher, Subscriber pattern. There are noteworthy additional constraints. A promise is a broadcast publisher. Multiple observers can be notified. Promises also guarantee exactly one resolution, either to resolve or reject. Unlike PubSub, a promise will inform an observer regardless of whether it begins observing before or after that one resolution has been dispatched. Unlike an Event Emitter, promises guarantee asynchrony. Event emitters are typically synchronous, both on the DOM and in Node.js.

For the purposes of robust composition and security, a promise guarantees that all handlers will be called in separate events. This prevents a variety of ways a function can interfere with other entities that share the same call stack, like calling functions that close on state that has not necessarily been set up before a function returns, or to inspect their own stack to infer what other agents are doing.

Most JavaScript environments are not sufficient to satisfy the security guarantees of the promise design. Google Caja and DrSES are projects to create such environments. However, Q promises were designed to be compatible with the original design such that code written for users of Q could more easily be ported to such environments. For the same reason, Q, unlike other JavaScript promise libraries, is also designed like E promises based on a message passing “kernel” that allows them to be used to send messages to objects in other processes, returning promises for the results which can be used as proxies for further messages to the results.

  • http://en.wikipedia.org/wiki/Object-capability_model
  • http://erights.org/elib/capability/ode/ode-capabilities.html

jQuery adopted promises but only partially appreciated the prior art. The promises in jQuery were reevaluated around jQuery’s own event dispatch patterns, with multiple inputs and outputs by default, which breaks the analogy that a promise corresponds to the result of a function call, either the return value or the thrown exception. jQuery promises also do not capture exceptions, so it is necessary to explicitly create “rejections” if observers should be informed of a failure. This makes it impossible for some agents to recover from certain errors. jQuery also decided to follow Dojo and Twisted in conflating the promise and resolver into one object, which was intended to make the interface easier to use. jQuery promises did not originally create new promises for the return value of the fulfilled or rejected handlers, but that mistake was later rectified.

like image 174
Kris Kowal Avatar answered Sep 17 '22 13:09

Kris Kowal


is the above accurate?

Yes. You could say that jQuery.Deferred is a subclass of the jQuery Promise.

is it a design pattern of its own

Probably, but a badly chosen one. How Deferreds and Promises should work is as two separate interfaces - you either have the object that can resolve things or you have the object that gets resolved (and which you can observe). The deferred could even be seen as a builder for the promise.

like image 30
Bergi Avatar answered Sep 16 '22 13:09

Bergi