On 4/22/14, 12:24 AM, Joshua Cranmer 🐧 wrote:
I managed to, in one of my playground techniques, create a global using
a backstage pass and some xpconnect APIs, so it's not impossible but it
is damn annoying.

Right. If you don't have a global to start with, your life will _really_ suck if you want to use promises as they're being specced and implemented. :(

That's because promises are a JS-centric feature and JS _always_ has a global to work with, ipso facto....

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 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.

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?

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. :(

I think I would consider adding helpers to xpconnect before doing raw
JSAPI

Sold!  ;)

I couldn't figure out how to pass undefined to a JS::Handle<JS::Value>.

JS::UndefinedHandleValue should do it. But yes, the docs are behind the times.

I don't think WebIDL is applicable in this circumstance if the JS
promises are coming from Promises.jsm...

Ah, if the JS code is not getting to create the promise, that complicates things a bit.

On the other hand, the JS code can always take the Promise.jsm thing it's given, call Promise.resolve() on it (the DOM Promise one, of course) and then end up with a DOM promise that will be resolved or rejected with the exact value the Promise.jsm thing is resolved or rejected with. Then return that to your callers.

but the problem is I have a lot of JS-implemented services that need to be
called from C++ which is where WebIDL is almost completely useless the
last time I checked.

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.

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.... ;)

-Boris
_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

Reply via email to