Why does jQuery's promise have a done(), but J

2019-06-21 10:49发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

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