slightlyoff / promises Goto Github PK
View Code? Open in Web Editor NEWDOM Promises IDL/polyfill
License: Apache License 2.0
DOM Promises IDL/polyfill
License: Apache License 2.0
I feel like I tried to bring this up earlier, but it deserves its own issue.
Futures-for-futures are hazardous in the following manner (via @briancavalier, indirectly via MarkM, I believe):
let future = new Future(({ accept }) => accept(5));
let futureForFuture = new Future(({ accept }) => accept(future));
let identity = x => x;
// With ordinary futures, this is a composable identity transformation:
let a = future.then(identity);
// That is, `a` will be accepted with `5` as its value, just like `future`.
// But with futures for futures, identity is broken:
let b = futureForFuture.then(identity);
// That is, `b` will be accepted with `5` as its value, but
// `futureForFuture` of course has `future` as its value.
// This prevents `identity` from being used as a no-op in the general case.
Do you agree that this is a problem? If so, I am happy to discuss solutions, as we have been doing over in Promises/A+ land. If not, /shrug.
Search for Cannot resolve a Future mutliple times.
Replace mutliple
with multiple
.
The latest version of Promise places the done() method with catch(). The problem is that under Google Chrome you cannot do the following:
futureInstance.catch(error)
{
window.onerror(error);
}
because window.onerror
is undefined, and you cannot throw error;
because the Promise will catch the error and translate it into a Promise.reject()
which is never handled.
In short, there is no practical way to cause errors to bubble up to the browser's default exception handler. Yes, I can log the error myself but I should be able to push exceptions to the default handler.
The Future interface currently has .value, .state and .error. It doesn't seem that those attributes are common in the Javascript libraries/definitions of promises [1][2][3]. Indeed, those values are simply useless because in a success or error callback, they are all known because of the context.
For example:
asyncCall().then(function(result) {
/* We know that:
- .value == result;
- .error == undefined;
- .state == "accepted" */
}, function(error) {
/* We know that:
- .value == undefined;
- .error == error;
- .state == "rejected" */
});
There is also:
var future = asyncCall();
/* At that point, we know that:
- .value == undefined;
- .error == undefined;
- .state == "pending". */
The only case where we might need to know what .value, .error and .state values are is this one:
var future = asyncCall();
methodThatWillProduceMultipleTripToTheEventLoopBeforeReturning();
// We no longer know the state of |future|, we might want to check with .state.
However, I believe that .then() should behave so that this is working:
var future = asyncCall();
methodThatWillProduceMultipleTripToTheEventLoopBeforeReturning();
future.then(function(result) {
}, function(error) {
});
The .then() method should work even if |future| was no longer pending. I we agree on that behaviour (I am not sure if the documentation specify that and, honestly, it is hard to read un-formated documentation), I think we could simply remove those three attributes and make the Future interface slimmer.
[1] http://wiki.commonjs.org/wiki/Promises/A
[2] https://github.com/kriskowal/q
[3] http://promises-aplus.github.com/promises-spec/
From experience with the Q library, when the 2 callbacks of the then are long, it isn't very clear where the onrejected starts.
Adding a .fail(function) gives a more declarative impression and is less ambiguous (doesn't need to keep track of indentation of a long function)
In the "reworked APIs" section, IDBRequest becomes a subclass of Future.
IDBTransaction behaves similarly, although it's not as simple a type as a IDBRequest. A transaction has a lifetime bounded by other asynchronous activity, after which it completes successfully ("complete" event) or fails ("abort" event), and in both cases action is likely to be taken by the script.
With current IDB you write:
tx = db.transaction(...);
tx.objectStore(...).put(...);
tx.oncomplete = function() { alert("yay, done"); };
I'd expect a Future-ish IDB to let me write:
tx = db.transaction(...);
tx.objectStore(...).put(...);
tx.then(function() { alert("yay, done"); });
... which of course gets more useful when you have join() operations letting you wait on multiple futures and all that other goodness.
After much investigation and discussion with Mark Miller, the decision regarding forwarding in accept()
is:
Future
to accept()
, the resolution of the "near" future is merged with the (perhaps eventual) resolution of the "far" future.acceptDirectly()
which allows Future
s to be accepted values, anticipating that this is the rare and exceptional case.Should callbacks for .then()
be invoked as though they are:
callback.call(future, valueOrError);
?
I think yes, but am flexible.
I am attempting to map the Geolocation API to the DOMFuture API, getPostition seems pretty simple. However the watchPosition API and the associated clearWatch are slightly troublesome.
Firstly, watchPostition is an asynchronous API that returns a value immediately (like setInterval and setTimeout) and then "onSuccess" is called multiple time as the position changes until you call clearWatch.
I am not sure how this maps to DOMFutures API, where to me at least, it seems very much like .then() will only be called once before passing to the next .then in the chain. Should I be using the Progress Future?
If we use the ProgressFuture, how should one handle the "watchId" so that the event can be cancelled. Would it be ok to assume the .value property returned is the watchId?
[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.
I like Future.then()
-style callback chaining but it has the nasty side-effect of mangling exception stack-traces in a way that makes code harder to debug.
Is it possible for the implementation to programmatically rewrite the stack-trace so Future.then(A).then(B).then(C)
ends up with a stack-trace that reads C -> B -> A
instead of C -> Future.wrap -> Future.pump -> anonymous function -> anonymous function
?
The current text implies that the Future and Resolver are conencted and that only the Resolver that creates a Future can eventually resolve it. To set up this linkage, we need some way to explain how that linkage is created without magic or ES6 @-names, since they're delayed to ES7 at the soonest.
One thought is that the Resolver might expose some callback-registration methods or even events. The Future will be passed the Resolver in it's ctor and automatically connect itself to the Resolver at creation time.
Thoughts? Preferences?
npm requires that package.json
be at the top-level a git repo for a node module. Could things be shifted around so that this command can be run successfully:
npm install git://github.com/slightlyoff/DOMFuture.git
One simple solution would be to just move the polyfill contents up a directory. These changes would also help people forking the repository and installing w/npm.
One question has nagged at me related to @domenic's question regarding cancelation. It seems that some APIs will with to return resolvers to expose the ability to resolve. The natural style of use is broken for these APIs:
// Note that we must dig out the future property in order to .then()
var r = doThing();
// ...
r.future.then(function(v) { ... }, ...);
// This doesn't work:
doThing().then(...);
To repair this, should a Resolver expose a .then() method which forwards to its .future's .then()?
E.g.:
Resolver.prototype.then = function() {
return this.future.apply(this.future, arguments);
};
If we do this, should returning a Resolver in a .then() also be treated the same way as returning a Future?
You cannot use "catch" as a function name because it is a reserved word. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
In terms of practical implications, Netbeans (and possibly other IDEs) treat it as a reserved word and parse/format the code accordingly leading to improper parsing/formatting.
Please rename this method.
It seems from the IDL that resolvers are not going to allow rejecting with non-Error
s. OK. But what about this sentence?
If the callback throws, resolve the returned future with an Error
What if the callback throws a non-Error
? E.g.
future.then(undefined, function () {
throw 5;
});
or worse,
future.then(undefined, function () {
throw undefined;
});
?
Background: https://github.com/domenic/promise-tests
It's painful to see that @domenic has bought off on Mocha/Sinon and the shit-show that is Node testing, but the test suite is comprehensive and we should ensure that, insofar as Promises A+ doesn't diverge further from DOMFuture, that we support its tests.
Doing this here because the mailing lists have turned into an unfollowable mess.
First, some cautionary notes: this thread will use the terms "wrapping" and "unwrapping" to refer to APIs that treat Future
s as something other than direct values. Posts here that use different terminology will be edited to conform.
Next, please be civil and cordial. Those who don't agree with you aren't bad and they might not even be wrong. Goodwill will get us where we want to go.
OK, down to it:
It seems to me that the contended bit of the design is .then()
(and by extension, .catch()
). Both pro and anti-unwrapping camps can have their own way at resolution time using .resolve()
and .accept()
respectively. And both have valid points:
On top of these points, there are preferences for styles of use. These can't ever be truly enforced with rigor because it's trivial to write wrapping/unwrapping versions of direct functions and vice versa. So there are cultural differences that we must admit with regards to preferred styles of use.
With the caveat that all involved are willing to live-and-let-live, I observe that it is possible to end the current debate in everyone's favor so long as we add a "direct" version of .then()
. That is to say, one which has the semantics of .accept()
with one level of unwrapping for a returned thenable and not .resolve()
(infinite unwrapping) for values returned from callbacks.
I'll submit .when()
as a straw-man name, but I'm not precious about it.
So the question now is: is everyone cc'd here willing to make such live-and-let-live compromise? And if not, why not? And is there some other detail which I've missed?
We're seeing the proliferation of DOMRequests in current specs. In recent example is the alarm API.
Discussion is probably needed, but I feel it's unlikely the FirefoxOS folks will move away from DOMrequests, because a lot of Gaia code relies on them.
A way forward is to make DOMRequest inherit from DOMFuture and ask everyone to move away from DOMRequests (or creating equivalents)
A number of the methods in this API (notably ResolverCallbacks) sport "raises(Error)" but the raises keyword is no longer in WebIDL. Exceptions are specified in prose rather than through the language itself.
Merging of returned Futures is a good feature, but by default it creates a lot of objects for the GC to clean up. I worry that our current design creates the need for alloc when it isn't strictly necessary. One way around this is to provide the resolver to the then callbacks, allowing them to drive the lifecycle of the vended future directly (vs. merging). Merging is, of course, still supported, but savvy then()
users could prevent mandatory alloc by returning the Resolver instead of a Future, signaling that they want to drive the process.
Crazy?
I'd like to propose the following design change:
Invoking accept
from a Resolver
invokes a hidden method resolve
if there are any chained Resolvers
, otherwise it invokes another hidden method finalAccept
.
This way users would only have to be aware of accept
and reject
. Currently we require users to invoke resolve
which I found to be very confusing. I shouldn't have to invoke different methods depending on whether chaining is taking place or not; that should be an implementation design.
@annevk recommends that it might be good to have an EventTarget
-free version of Future
specified here for use by Mozilla. I agree that we need it.
Currently the prolyfill uses this code for testing whether a value is a Future:
!!x && typeof x.then === 'function' && x.then.length === 2
The issue with "duck testing" is that, as @domenic raised in Issue #13, the type of a fulfilled future is not fully polymorphic: you must never fulfill with a future that you intended to be a completed value. Bottom line: there needs to be a super-clear and ideally super-simple definition of what it means to be a future.
I'll pitch a few alternatives here, but I make no claim to exhaustiveness. Other suggestions welcome.
[[Class]]
with an isFuture
testUsing instanceof
is traditionally brittle because when multiple frames interact, they can have multiple, mutually incompatible versions of a given "class." That's why ES5 introduced Array.isArray
as a way of testing whether something has the [[Class]]
"Array", which is robust across frames, even when they have different Array
constructors. So an analogous approach would be to introduce a new "Future" [[Class]]
and an isFuture
test that inspects the class. This is very clear and very robust, but has the downside that you can't create futures conveniently with an object literal.
Symbol
to definitely brand futuresAnother approach would be to create a unique symbol (a new ES6 feature for creating opaque unforgeable property keys) that's shared in the standard library and identical across all frames. Then to create a future you would have to have this symbol, a la:
var myFuture = {
[futureSymbol]: true,
then: function(/* ... */) { /* ... */ },
// ...
};
A lower-tech approach is to have some sort of published key that is simply a standard string key, but perhaps distinctive enough that it's highly unlikely (though still possible) that someone could accidentally create one. For example, Promises/A+ discussed alternatives like p.then.aplus
or p.isPromise
.
This approach is certainly the easiest, but I would hope we could do better when we have the opportunity to define this in the web platform and/or ES standard. What's particularly galling about it is that it effectively declares that whatever public key it's using is once and for all permanently associated with this typeโthat's global pollution of the entire JavaScript language. Scumbag futures!
We could always just do what the prolyfill currently does. Again, while it's unlikely that someone would accidentally fulfill a value that is not intended to be a future but looks like one, that doesn't mean it can't happen. For example, you might be writing future-aware code that nevertheless fulfills with the result of calling some third-party code, and passes it back over to some other third-party code. And those third-parties may not be future-aware. If they happen to be using values that look like futures, not only will the program be buggy, it'll be buggy in badly unpredictable ways.
See also:
Dave
Future no longer inherits from EventTarget but EventedFuture still does. It is not clear what is the use case of that interface.
Using .then() for Future seems to be preferred over DOM events. For example, it looks like node moved from an event based system to something else [1]. To be fair, their event based system wasn't allowing .then() but the point is that we can deduct that developers do not like event based system for promises.
Also, it is not clear what would DOM events add to the Future interface. With events, the developers would be allowed to do:
// First:
asyncCall().onaccepted = function() {
};
// Second:
asyncCall().onrejected = function() {
};
// Third:
var future = asyncCall();
async.onaccepted = function() {
};
async.onrejected = function() {
};
Which can easily be expressed that way:
// First:
asyncCall().then(function() {
});
// Second:
asyncCall().catch(function() {
});
// Third:
asyncCall.then(function() {
}, function() {
});
Using DOM events doesn't make the code easier to understand or to write. It actually removes the ability to chain calls and introduce a terrible confusion because .onaccepted and .then() do not actually behave the same way.
If you do:
var future = asyncCall();
spendTimeDoingStuffAndTripsToTheEventLoop();
// The future has been accepted.
future.onaccepted = doSomethingWhenAccepted();
and:
var future = asyncCall();
spendTimeDoingStuffAndTripsToTheEventLoop();
// The future has been accepted.
future.then(doSomethingWhenAccepted);
In the first snippet, doSomethingWhenAccepted() will never be called but in the second snippet it will.
I think it would be better to prevent that kind of inconsistency and not have this EventedFuture interface.
Firstly, sorry if this sounds stupid.
In my hackjob of a reworking of the Geolocation API, I am trying to determine where the values passed in to "then" or "done" are defined.
The Geolocation spec has http://www.w3.org/TR/geolocation-API/#position and http://www.w3.org/TR/geolocation-API/#position_error_interface objects which are only ever used when passed into the success or error callbacks.
I think (I could be wrong) that in the current model of DOMFutures, their usage in the spec is left hanging? i.e, they might be defined but there is no usage in the IDL for them.
Is it expected that authors will create a {X}Future IDL for their API by either specifiying that the accept callback takes a API{X} specific object, or that done
and then
will be defined more deeply for the API?
For example, Geo might have a GeoIDL of:
dictionary Position {
/* what ever the spec defines */
};
dictionary PositionError {
/* what ever the spec defines */
};
callback GeoCallback = void (Position);
callback GeoErrorCallback = void (PositionError);
interface GeoOperation : DOMFuture {
void done(optional GeoCallback onaccept, optional GeoErrorCallback onreject);
void then(optional GeoCallback onaccept, optional GeoErrorCallback onreject);
};
Is this along the correct way of thinking or am I miles off?
This is a fairly innovative approach to cancellation. However, I'm not sure it allows the use cases one might hope for. E.g. how could a future-returning XHR method allow you to cancel the XHR?
var xhrFuture = doXhrPostWithLotsOfData(options);
xhrFuture.then(function (whatever, resolverForXhrFuture) {
// I want to call `resolverForXhrFuture.cancel` to cancel the POST upload,
// but I'm not even called until way after it's finished!
});
Some examples of how you anticipate cancellation working would help clarity a lot.
From experience, that's necessary to use promises effectively.
Yes, people can write it as a library... in which they'll do off-by-one errors or equivalent.
Since reject can take any value, that should be sufficient
At a minimum, it should have a non-conflicting name with whatever global DOM eventually defines.
The bikeshed is now open. FuturePolyfill
? PolyFuture
?
Hi!
I noticed the polyfill is checking for the existence of both the then
and done
functions in an object. Why check for done
? Pretty much every implementation out there is only checking for then
. Examples:
Given:
function third()
{
return new Future(function(future)
{
console.log("third");
future.resolve();
}).then(function()
{
console.log("third.then")
});
}
function second()
{
return new function()
{
console.log("second");
return third().catch(errorHandler);
};
}
return new Future(function(future)
{
console.log("first");
future.resolve(second());
}).then(function()
{
console.log("first.then");
});
I am expecting the following output:
first
second
third
third.then
first.then
but first.then is missing. If I comment out .catch(errorHandler)
I get first.then as expected. It seems that .catch() is blocking .then().
Expected behavior: .catch() should intercept errors thrown by child Futures, but allow control to bubble up to parent Futures on success.
The .then
and .done
already take care of registering callbacks.
Futures can be seen as an idomatic construct built on top of promises, paving the cowpath of a very recurrent pattern (make a request which succeeds or fail)
It turns out that allowing extensibility via the callbacks
parameter only exacerbates the lack of it in .then()
's signature. E.g., if you add a progress
callback to a subclass, how does one register to hear about it in .then()
? Today, you fight over a 3rd positional parameter, which is as inelegant as the same fight in the API of Future
.
One idea sparked from coversation with @jakearchibald is to allow a mirroring bag of callbacks in the signature of .then()
.
You might then write something like:
f.then({ accept: function(v) { ... },
reject: function(e) { ... },
progress: function(...) { ... },
// other extensions here...
});
We could still restrict who can comment I suppose, but it would be nice to point others to it, e.g. Jonas Sicking.
It's probably worth noting somewhere that calling dispatchEvent (with the future-related events) after resolution will fail in some way.
Both in the current IDL:
// No matter what approach is pursued, integration with developer tooling is
// key. Developer consoles SHOULD log un-caught errors from future chains.
// That is to say, if future.done(onresponse); is the only handler given for
// a resolver which is eventually rejected, developer tools should log the
// unhandled error.
...
// An end-of-chain callback. Equivalent to .then() except it does not generate
// a new Future and therefore ignores the return values of the callbacks.
and in @DavidBruant's message:
.done to end the chain (and have the devtools report uncaught errors at the end of the chain)
I see some confusion over how done
and unhandled exceptions are expected to work. Let me outline how I envision them, and how they work in current promise libraries, which I think is better than---or at least clearer than---the sentiments expressed above.
See promises-aplus/unhandled-rejections-spec#1 for a more in-depth explanation if the below doesn't immediately make sense to you.
If you do this:
let future = new Future({ accept, reject } => reject(new Error('boo!')));
you have created a promise with an unhandled rejection. This is equivalent to the synchronous code
let result = (() => throw new Error('boo!'))();
Of course, the synchronous code would hit window.onerror
, since nobody's there to catch it. But we can't do that with promises, because they are first-class values who we can give to someone else who might handle them, say, after 100 ms.
This is the essential problem, in a nutshell. If nobody ever attaches a rejection handler, errors will go unreported and be silenced. Bad!!
done
solutionSee promises-aplus/unhandled-rejections-spec#5 for a more in-depth explanation if the below doesn't immediately make sense to you
One solution is to have a rule that you enforce on promise users and creators: always either
return
the promise to your caller, or;done
to signal that the buck stops here, and if there are any unhandled rejections, they should hit window.onerror
.That is, done
is essentially:
Future.prototype.done = (onaccept, onreject) => {
this.then(onaccept, onreject)
.catch(reason => setImmediate(() => throw reason));
};
This rule is pretty good, and used in Q and in WinJS promises with some amount of success. @lukehoban has previously remarked that it ends up not being as much of a burden on developers as you'd initially think, and I agree.
But, it's still error-prone: if you slip up and don't follow the rule even once, you might silence an error forever.
See promises-aplus/unhandled-rejections-spec#2 for some speculations on how to implement this solution in current promise libraries.
This solution involves the dev tools having a hook into the promise library, such that any time an unhandled rejection is created, they are notified. But more importantly, whenever an as-yet-unhandled rejection becomes handled, it notifies the dev tools of that.
With this in hand, you can imagine a panel in the dev tools that shows outstanding unhandled rejections, dynamically adding them as they are created and removing them as they are handled. If they stick around for too long, you know there's a problem.
One way of thinking of this is as an "erasable console.log
", i.e. if we could just console.log
the unhandled rejections, but then when they get handled, "erase" that entry we wrote to the log. Indeed, Q implements something like this using the fact that when you log arrays in Chrome, they are "live" and auto-update as the array changes. So we log the array of unhandled rejections, and add/remove from it as appropriate. If you ever see a non-empty array in your console for too long, you know there's an issue.
This solution was mentioned to me by @erights. Using something like the weak references strawman, promise libraries could maintain a table mapping promises to unhandled rejections. Once the promise gets garbage collected, and the weak ref thus points to nothing, it logs those unhandled rejections.
Unfortunately this cannot be implemented in terms of weak maps, from what I understand. You need the garbage-collection observability which weak maps specifically do not provide.
So, hope that was clarifying. I think the current IDL doesn't express how done
is meant to work very well, and seems to tie dev tools to done
, whereas they are actually separate and somewhat-complementary solutions.
Hope this helps!
Currently, throwing an exception inside a Future
triggers an uncaught exception.
Instead, I am proposing that throwing an exception should trigger Resolver.reject(exception)
so that if there is an error handler registered, it be allowed to handle the exception.
This also results in cleaner code. Consider:
return new Future(function(future)
{
if (!uri || typeof(uri) !== "string")
throw new TypeError("Invalid uri: " + uri);
if (!department || typeof(department) !== "string")
throw new TypeError("Invalid department: " + department);
...
}
versus:
return new Future(function(future)
{
if (!uri || typeof(uri) !== "string")
{
resolver.reject(new TypeError("Invalid uri: " + uri));
return;
}
if (!department || typeof(department) !== "string")
{
resolver.reject(new TypeError("Invalid department: " + department));
return;
}
...
}
For background and details, see
http://lists.w3.org/Archives/Public/www-dom/2013JanMar/0202.html
http://lists.w3.org/Archives/Public/www-dom/2013JanMar/0205.html
In short, in some cases we need the ability to resolve a Future synchronously. In particular, for some APIs it's important that the callback which indicates success/failure happens at a particular instance.
For Event dispatch, it's important that the callback is called during the actual event dispatch. Otherwise doing things like calling Event.preventDefault() or Event.stopPropagation() will have no effect.
There will likely be other similar scenarios. I could definitely imagine that we'll run into situations when we'd want to do something like:
function topLevelCallback() {
setState1();
resolver1.accept(...);
setState2();
resolver2.accept(...);
setState3();
}
where topLevelCallback
is called as a separate microtask and where we want the callbacks which are triggered by resolver 1 to see "state 1" and the callbacks triggered by resolver 2 to see "state 2".
Ideally the cases when we need to synchronously resolve a Future will be rare and will only happen when we're basically at the top of the callstack. Synchronously dispatching Events is an obvious exception and really is a wart, but one that we're many years too late to fix.
I think we're pretty close to consensus on the most pressing issues (modulo #11, the MOST IMPORTANT ISSUE OF ALL). The polyfill and tests aren't done and I won't likley have time to get to them until next week at the earliest. What is the feeling of those who have been paying attention to this repo about opening it up now? Is there a compelling reason to wait any longer?
Given that errors or values can be undefined
or null
, this comment is no longer accurate. The state
property is probably sufficient to distinguish.
// markm points out that we need to be able to distinuish between all
// available states:
//
// pending (cancelled == false && value == null && error == null)
// accepted (cancelled == false && value != null)
// rejected (cancelled == false && value == null && error != null)
// cancelled (cancelled == true);
The current design squats on the name Future
, potentially precluding others from defining it sanely in ES5 contexts. This is potentially problematic as one goal of this proposal is to allow ES7 to specify a subset of the behavior we outline in a JS-standard Future
type. Should we move Future
to DOMFuture
?
We currently have:
Future then(optional AnyCallback onaccept, optional AnyCallback onreject);
My reading of WebIDL is that the above does not allow you to call:
fut.then(null, errCB);
("Web IDL operations do not support being called with omitted optional arguments unless all subsequent optional arguments are also omitted.")
I know that there's catch
for that case, but it can lead to unpleasant code when you're getting the callbacks from somewhere else. To give an example, I bumped into that issue recently in which I had to support an interface that could accept success and error callbacks and needed to return a future. I ended up with the equivalent of:
function (foo, successCB, errorCB) {
var fut = new Future();
if (errorCB && !successCB) fut = fut.catch(errorCB);
else if (successCB) fut = fut.then(successCB, errorCB);
return fut;
}
Not dreadful, but ugly and annoying. Instead we could have:
Future then([TreatUndefinedAs=Null] optional AnyCallback? onaccept, [TreatUndefinedAs=Null] optional AnyCallback? onreject);
Or something along those lines.
Having documented a bunch of WebAPIs implemented in FirefoxOS, I've noticed that a lot of methods return a DOMRequest. But nobody cares. What people care about is not the value they get immediatly, but the value the get eventually. It would be good if WebIDL was expanded to accept the following notation:
interface I{
DOMFuture<File> getFile(in DOMString name);
}
I'm not 100% sure it's relevant for this repo, but it'd be good to keep this in mind.
event
object as a first parameter to callbackEventTarget.prototype.once = function(eventType, options) {
var self = this;
return new Future(function (resolver) {
self.on(eventType, options, function(event)) {
resolver.accept(event);
});
});
};
EventTarget with DOM Future someway, somehow, should support handleEvent. Right now I can write:
var model = {
handleEvent: function(e) {
var handlerName = "$" + e.type;
if( handlerName in this ) {
return this[handlerName](e);
}
}
, $click: function(e) {
console.log(e.type)
}
, $mouseover: function(e) {
console.log(e.type)
}
, init: function(node) {
for( var eventName in this ) {
if( eventName[0] == "$" ) {
node.addEventListener(eventName.substr(1), this);
}
}
}
}
model.init(document.find(".some_node"));
or
var xhrController = {
handleEvent: function(e) {
switch(e.type) {
case "load":
//do something
break;
case "abort":
//do something
break;
default:
console.log(e.type, e);
}
}
, init: function(xhr, url) {
this.xhr = xhr;
this.url = url;
["load", "error", "abort", "loadend", "loadstart", "progress", "timeout"].forEach(function(name) {
xhr.addEventListener(name, this);
}, this);
}
, send: function(data) {
xhr.open("POST", this.url);
xhr.send(data);
}
}
xhrController.init(new XMLHttpRequest({anon: true}), "//example.com/");
or even
var rootClickEvents = [];
document.addEventListener("click", rootClickEvents);
//somewhere in script
rootClickEvents.handleEvent = function(e) {
this.forEach(function(handler) {
handler.call(e.currentTarget, e);
})
}
//...
rootClickEvents.push(function(e) {
console.log(e.type, e);
});
In DOMFuture proposal it doesn't even mention the handleEvent
.
I think event
object should contains a Future/Promise state information.
"Chaining fast-forwards un-handled values to the end of the chain." - is it always the end of the chain?
asyncTask().then(function(val, nextResolver) {
throw new Error("BAM!");
}).then(function() {
console.log('Ok 1')
}).then(function() {
console.log('Ok 2');
}, function() {
console.log('Error 1');
}).done(function() {
console.log('Ok 3');
}, function() {
console.log('Error 2');
});
What gets logged here?
Hi,
I'd like to publish this Javascript file using http://www.webjars.org/. In order for users to reference your library, I need to introduce some sort of version number or tag.
Is it possible for you to tag future releases?
While implementing Promises i had some problems on making resources eligible for garbage collection. The typical use cas is the Promise.some method. Let's consider this code :
var p= Promise.some(
new EventPromise(document,'click'),
new EventPromise(document,'keypress'),
new EventPromise(document,'touch')
).then(function() {
// start my app
});
Internally, the EventPromises are registering callbacks to the DOM document. So, it's callbacks will stay in memory during all the application life cycle. Knowing that the promises are unique operations, it could lead to important memory consumption for applications. XHRPromises could lead to very important memory leaks cause they often retrieves a huge amount of datas.
That's why i think we should let the resolver function return a "disposer" function that would let the Promise.some method dispose cancelled Promises.
The main advantage of this method is it keeps backward compatibility while it allows the dispose function to be propagated througth promises trees.
It implies 2 things :
Thanks for reading.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.