backbone icon indicating copy to clipboard operation
backbone copied to clipboard

v2: Can of Promises

Open au-phiware opened this issue 10 years ago • 9 comments

I'm a big fan of Backbone and of Promises, this is my take on combining the two.

I understand that this may be a can of worms and I have changed many, many functions and it may not be your cup of tea. For this reason I have also made sure all the tests pass (with changes, of course) and I have tried to be backwards compatible (the Todos app still works). I haven't added any new tests yet but I would like to, as use cases arise and as I start to use this code in my own projects.

I have many use cases in mind and have already started with my own major changes: for instances Router#execute will catch errors and trigger an error event (on the router). My intention is that route actions should return the promise(s) from other methods (like render), this will mean that no error gets swallowed or forgotten about.

I'm making this PR, ignorant of the opinions of others (I've only just realised that there are already discussions about this) but keen to learn those opinions and to get some feedback.

I have made some assumptions:

  • Promise, as per ES6, is a global object. In my view it's very easy to include the standard polyfill.
  • jQuery.Deferred is not Promise and needs to be avoided.
  • Promises are useful outside of database interaction.

That last point is important to me. I am currently working on a big project that uses requirejs and pouchdb/couchdb. We use promises to orchestrate module dependencies as well as data from the server, whereby a Promise is created inside initialize and then is called inside render.

au-phiware avatar Jul 24 '15 12:07 au-phiware

I'm sympathetic to this changeset and think a movement like this may be a good way to move backbone forward (along with @jmeas' proposed router changes) in v2. So a hesitant :+1: after this has been carefully reviewed

megawac avatar Jul 26 '15 02:07 megawac

I get 7 failed tests when I use either this branch or the jashkenas/master branch.

au-phiware avatar Jul 26 '15 07:07 au-phiware

Also, there is significant overlap with https://github.com/jashkenas/backbone/pull/3651

megawac avatar Jul 26 '15 16:07 megawac

I think this pull really showcases some of the downsides of Promises (and asynchronicity in your code in general) in that once you use them in a few places, you practically have to make your entire API asynchronous.

I see very little reason for Model#defaults or Router#execute, to give two examples, to be asynchronous. That's not the right place for network or user-facing code to exist. You're contorting Backbone's API — and by extension your code — to fit a small assortment of problems that are better handled elsewhere.

I'm fully in support of wrapping asynchronous calls (sync is the biggest one) in Promises, however.

akre54 avatar Jul 27 '15 15:07 akre54

Ha! Perhaps I should have added: "WARNING: May cause Scoliosis"

But on a serious note, I don't like the isPromise checks but I think there's power in giving the option to have a value, a function or a Promise at those points. IMO, writing with Promises demands a different way of thinking. Remember that a Promise does not represent an async call, instead it is simply a dependency on an async call, which could have been fulfilled at any poiny in the past. So it is not correct to assume that whereever there is a Promise there will be a network call or something else that hasn't happen.

So I agree that defaults is not the right place to be accessing the network, etc. But I can't dictate that it can't be time dependent on something else.

au-phiware avatar Jul 28 '15 01:07 au-phiware

Sorry, that close was a slip of the thumb...

au-phiware avatar Jul 28 '15 01:07 au-phiware

Scoliosis

Ha. @paulmillr made a fork of Backbone a while back called Scoliosis (since renamed Exoskeleton). Maybe we could implement it there first.

Remember that a Promise does not represent an async call, instead it is simply a dependency on an async call, which could have been fulfilled at any poiny in the past.

Right of course. But it starts to get ugly fast when you mix sync and async code using promises. In my experience they tend to take over your entire application when really you should've been writing it reactively in the first place.

I don't like the isPromise checks but I think there's power in giving the option to have a value, a function or a Promise at those points.

There's power but there's also a great deal of sloppiness. You know what Ben Parker (and Teddy Roosevelt) said about power and responsibility...

So I agree that defaults is not the right place to be accessing the network, etc. But I can't dictate that it can't be time dependent on something else.

Can you give an example?

akre54 avatar Jul 28 '15 02:07 akre54

I think if we want to return a promise it would be good to pass parsed response to then's callback. Read more at https://github.com/jashkenas/backbone/pull/3779

godlark avatar Aug 28 '15 14:08 godlark

The sync method in Backbone 1.x returns promise using the interface of jQuery.Deferred. Be careful with switching to Promise/A interface in the result of this method. It would be a breaking change. You should schedule it for Backbone 2.x.

prantlf avatar Jan 07 '18 23:01 prantlf