slightlyoff / Promises

DOM Promises IDL/polyfill
Apache License 2.0
154 stars 28 forks source link

Expanding DOMFutures #30

Open DavidBruant opened 11 years ago

DavidBruant commented 11 years ago

[http://lists.w3.org/Archives/Public/public-sysapps/2013Feb/0121.html](some thoughts). I don't know if that belongs to the core DOMFuture spec. Maybe a non-normative section. Maybe a different document where other advice on how to design an API would be listed.

I'm creating the issue mostly to share the thoughts and discuss if there is agreement on the advice and whether that belongs to the DOMFuture spec.

slightlyoff commented 11 years ago

I've got a quick sketch of an extension for progress events here: https://github.com/slightlyoff/DOMFuture/blob/master/ProgressFuture.idl

I expect that DOMFuture is a broadly-compatible base-class that many, many specs will extend to suit their needs.

domenic commented 11 years ago

Here is an example implementation of cancellable promises as a subclass of normal promises: https://github.com/promises-aplus/cancellation-spec/issues/6

You have to tilt and squint your head a bit to make it work with DOMFuture, but the main idea is the same.

slightlyoff commented 11 years ago

Cancellation means leaking a capability...which is totally legit. Here's the quick-and-dirty variant:

var vendCancelable = function() {
  var f = new EventedFuture(function(r) {
    // ...
    f.cancel = function() { r.cancel(); };
  });
  return f;
};
var f = vendCancelable();
f.cancel();

The IDL isn't as clear about what would be going on, but the idea is the same; define a "subclass" that tacks a cancel() method onto the Future which through a privileged channel invokes the associated resolver's cancel().

domenic commented 11 years ago

@slightlyoff Right, but, cancellation doesn't propagate with that solution, and it doesn't show how to use cancellation usefully for e.g. aborting an XHR. (Also, it breaks because f is not initialized at the time function (r) { ... } is called.)

Here's a variant of your code that illustrates the propagation problem (while fixing the how-to-use-for-aborting and f-not-initialized problems):

function get(url) {
  const xhr = new XMLHttpRequest();
  let cancel;
  const future = new Future(
    (callbacks) => {
      xhr.open("GET", url, true);
      xhr.onload = () => callbacks.resolve(request.responseText);
      xhr.onerror = () => callbacks.reject(new Error("Can't XHR"));
      xhr.send();
      cancel = callbacks.cancel;
    });

  future.cancel = () => {
    cancel();
    xhr.abort();
  };

  return future;
}

get("http://example.com/user.json").cancel(); // works

function getJSON(url) {
  return get(url).then(JSON.parse);
}

getJSON("http://example.com/user.json").cancel(); // doesn't work, no `cancel` method.

Cancellation is pretty useless if you lose it the moment you chain off the promise, thus the more complicated implementation in https://github.com/promises-aplus/cancellation-spec/issues/6. You can of course demand that consumers of cancellable promises attach their own cancel methods which delegate to the original promise, but that's not too ergonomic IMO.

Thoughts?