petkaantonov / bluebird

:bird: :zap: Bluebird is a full featured promise library with unmatched performance.
http://bluebirdjs.com
MIT License
20.45k stars 2.33k forks source link

Document a compatibility path for cancellable promises #117

Closed yuchi closed 10 years ago

yuchi commented 10 years ago

I’m a library producer, and I’d like my module to have both a cps and a thenable interface. Most of the asynchronous operations will be IO and for this the ability to cancel the promise is really—I mean really—important. I don’t want to include bluebird in my library, but I want it to support a consumer using bluebird.

Could we reach a compatibility checklist to produce thenables/promise-like things that bluebird will treat as cancellable?

Related SO question

benjamingr commented 10 years ago

This is an interesting question, I don't think this is really the right place to ask about standardizing cancelation and a spec.

There is https://github.com/promises-aplus/cancellation-spec/issues which discusses exactly this. This is the specification Bluebird implements and the tests it passes. AFAIK other big libraries that support cancellation do the same. It's also still in draft stage.

I'll ask more relevant people about this and let you know :)


Also, not as related: I don't like the idea of having to write a callback and thenable interface. I hope you're writing one yourself and generating the other.

Promise.promisifyAll is almost as fast as hand writing your promise code since it uses dynamic compilation to generate a function for the promisified API. From a maintainability perspective, I'd do it the other way. I'd write a promise API and use .nodeify() or even just inform users of it in the API docs.

( That is, expose a promise API and explain interactions with callback interfaces using .nodeify )

benjamingr commented 10 years ago

To make it clear, as far as I know Bluebird does not support assimilating cancellable promises at the moment.

yuchi commented 10 years ago

Just to make things even clearer, so probably I could also shed some light on my specific issue, this is the situation for me:

  1. I’m building a connector to an RPC-like web service
  2. I need to bundle a HttpClient wrapper to support Node.js, the browser (via browserify), and Titanium SDK
  3. The wrapper will (probably) visionmedia’s superagent, which offers both a .end(callback<err,response>) and a .on('success', cb).on('error', cb) interface
  4. I’ll need to do a lot of mangling of the data recieved
  5. I’ll need to rewire success and errors (the server sometimes give me 200 for actual exceptions…)
  6. This is going to be used on mobile projects where canceling useless requests can really make a difference

For this I really hoped to be able to include a small (as small as possible) promise-polyfill with support for cancellation, use it to mangle data as needed, and build around it the other APIs (EE-based and cps).

Including bluebird still looks overkill for me… what do you think?

benjamingr commented 10 years ago

There have been considerable efforts by Mark Miller and Kris Kowal has this neat thing to perform RPC like calls using promises.

Have you seen https://github.com/kriskowal/q-connection ?

I think some people here are a lot more experienced with RPCs with promises and I hope they'll give their input.

( For what it's worth, I don't think including Bluebird is overkill here but it might not be the best tool for this specific task)

domenic commented 10 years ago

I am almost certain it is not going to be possible to encapsulate cancellation behavior into a thenable. In general, having your library produce thenables is an antipattern. They are meant as a crutch for dealing with poorly-behaved libraries like jQuery, and not for promise-aware libraries to produce.

If I were creating a library that did not want to produce promises, I would just expose Node-style callbacks, and rely on conversion code to make it work. Whereas, if I wanted features of promises, including cancellation, I would just return real promises.

benjamingr commented 10 years ago

Just to strengthen what @domenic said - when I said Bluebird might not be the right tool here it's because you might enjoy the built in RPC in q-connection, not because I was implying you should not use a promise library.

You should use a promise library regardless, and if you're not using q-connection I think Bluebird is a very solid choice.

yuchi commented 10 years ago

Ok, I’m almost but not quite, entirely unlike going to include bluebird as a dependency and use .nodeify.

But if bluebird could assimilate (and the spec permitted it) thenables with a cancel method and let .cancellable() to make promise.cancel proxy to assimilated.cancel, then…

(gosh I speak in promises)

domenic commented 10 years ago

Maybe I wasn't clear. I don't think it's technically possible to construct a thenable which could be assimilated by a promise library and still retain cancellation functionality. This isn't spec-related, or Bluebird-related: I just don't think it's possible at all.

yuchi commented 10 years ago

I need to get myself into the internals of the assimilation process, and probably build a POC myself, before I can make any statement on this. For now I’ll stick with bluebird. Thnak you for the responsiveness!

petkaantonov commented 10 years ago

That was supposed to be #118 , not #117 :P

yuchi commented 10 years ago

Your test case incorrectly states that it’s related to gh-117 :)