On 4/22/2014 12:46 AM, Boris Zbarsky wrote:
On 4/22/14, 12:24 AM, Joshua Cranmer 🐧 wrote:
I consider Promise more like a generic platform feature (considering
that the specification is moving to ES6 instead of DOM)
ES assumes you always have a global. In fact, until ES6 it assumed
that there was only one global around, so of course you could always
get access to this singleton global. ES6 is introducing Realms (read
globals), but still assumes that any time any code is running that
code is associated with a realm and knows what realm that is....
(except maybe insofar as things like
realms/compartments/etc. are concerned)
That's a pretty huge exception.
I'm giving to thinking in terms of all of the magic hiding that
XPIDL/XPCOM/xpconnect does, so things like "what is my global object"
being intrinsically important are annoying to me. Now, clearly, I don't
expect to be able to create a DOM element without a reference to a
Window or an XHR without one since their concerns are clearly tied to
specific window properties, but something like Promises or TextEncoder
which is more or less like "syntactic sugar for code I could write but
don't want to" (excluding Promise's dependence on "run this on the next
event tick," I suppose).
I think there are proposals to
add it to XPCOM JS component/module scopes, which to me is the
definition of "should be usable outside of web platform APIs."
"web platform APIs" would include ES6 Realms.
Component/module scopes have an nsIGlobalObject... and a Promise
constructor, for that matter.
When I create an nsIJSImplementedInterfaceMagicObject from C++, I don't
have to worry about global objects. Perhaps xpconnect should just expose
the "here's a dummy global if you need one" more easily?
But that's only true if it's an actual Promise.
OK. Why is the thing you have not an actual Promise? Where did this
thing come from?
I've heard that Promises.jsm are still better to use than DOM Promises...
For more specific explanation then:
I have a (non-negotiably) JS-implemented XPCOM service called the Folder
Lookup Service. I want to add an API to it called getOrCreateFolder that
returns a Promise<nsIMsgFolder>. I have non-negotiable C++ code that
wants to call this method, and do something when the promise is resolved
or rejected.
Thank you for explaining what you're trying to do.
The JS implemented XPCOM service can call |new Promise| (or any of the
Promis static methods) to create an actual DOM Promise object, since
we install that constructor on all XPConnect globals.
You can have getOrCreateFolder return "jsval" in the xpidl, then
manually unwrap to a dom::Promise in the C++ like so:
if (!value.isObject()) {
// Throw
}
Promise* promise;
nsresult rv = UNWRAP_OBJECT(Promise, &value.toObject(), promise);
if (NS_FAILED(rv)) {
// Throw
}
Then you can call promise->AppendNativeHandler() with a handler you
implement. At least assuming your code is in libxul. If not, we may
need to add some symbol exported from libxul or a virtual function on
Promise that lets you make this call.
That leaves the problem of extracting the nsIMsgFolder from the value
you'll get resolved with, of course... nsIXPConnect has some methods
for doing that sort of thing, like getNativeOfWrapper(), but they're a
bit of an annoyance, I agree. I'd try harder to solve this problem if
any solution were not going to be jettisoned when Promise moves into
SpiderMonkey. :(
ToJSValue I think makes some of the pain of converting from T (for
almost any xpidl-usable type, at least) much less painful. A
corresponding FromJSValue could probably work well too. With something
like those methods, I can probably do C++ magic that autogenerates the
PromiseNativeHandler stuff for a generic nsresult nsFoo::DoX(U, V&);-ish
method. When I have some more time, I can try playing with some magic
prototype implementations and suggest which methods would be sufficient
to be useful for my needs.
WebIDL is totally happy letting C++ call into JS. You just declare a
callback interface, and get a generated C++ class that you can call into.
The missing piece is that this C++ class needs to be created with a
JSObject* pointing to the JS thing it needs to actually talk to.
We've considered factoring out the "hunt down the object" thing from
XPConnect's JS component loader so it's easier to reuse here, but for
now used the "createInstance an nsISupports, then dig out the
JSObject* from it" thing that dom::ConstructJSImplementation does.
We could add some IDL annotation that would let you get a C++ callback
interface representation for a JS-implemented XPCOM service or some
such, basically by running code like ConstructJSImplementation, but
with getService instead of createInstance, if this is something people
will want reasonably often. Note that unlike XPCOM services this
would NOT give you the same pointer identity every time you call it;
doing that would involve more annoying machinery that I'd like to not
add unless it's really required.
The IDL annotation I think I'd want first is not defining these in the
mozilla::dom namespace. ^_^ I don't think I care about pointer equality
for services (just that services aren't created more than once),
although if getting the service is kind of expensive, it may make sense
to cache the service. For most of the new code I'm adding and/or
rewriting, I'm largely sticking the access of these resources behind
custom C++ methods instead of using the xpidl directly anyways (xpidl
and arrays simply do not get along at all).
It might help if you ping me on IRC instead of trying to go back and
forth on the newsgroup...
Sure, if I had time today for in more than 15-minute snippets. But I'm
technically on PTO, so I don't. I could have waited a few more days
until I got back before responding at all, I guess.... ;)
Heh, I didn't realize you were on PTO, having better response times than
I do when I'm not on vacation :-P
--
Joshua Cranmer
Thunderbird and DXR developer
Source code archæologist
_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform