Closed Bug 1055144 Opened 11 years ago Closed 11 years ago

Update Messaging.jsm API to use promises

Categories

(Firefox for Android Graveyard :: General, defect)

All
Android
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED
Firefox 35

People

(Reporter: bnicholson, Assigned: bnicholson)

References

Details

Attachments

(2 files, 1 obsolete file)

Promises offer a number of advantages over callbacks, such as safer error handling and cleaner code. One of the most common async operations for Android is sendMessageToJava, which uses callbacks for the response. Let's update this API to use promises.
TBH, I intentionally wrote it this way originally because its super easy to wrap in promises if you want: return new Promise(function(resolve, reject) { sendMessageToJava(msg, resolve, reject); }); but doesn't require them if you don't.
Attached patch Implement sendRequestToJava (obsolete) — Splinter Review
Renames sendMessageToJava(message, callback) -> sendRequestToJava(message). I know you'd probably prefer using the same function name for both like we do now, but we can't do that using promises since there's no way to tell whether the message is a request or not given a single message argument. By splitting this into two separate functions, we also have more parity with our Java-side API. I removed the "cancel" callback since a request should be an all-or-nothing scenario; either you get what you asked for or you don't. "cancel" essentially just eats the request, which could leak resources if caller is expecting a response. Note that I added sendRequestToJava as an exported function in this patch, but it's pretty terrible adding more global exports in that module. I'm fixing this in bug 1043633; ideally, these will land together.
Attachment #8474672 - Flags: review?(wjohnston)
Blocks: 1043633
(In reply to Wesley Johnston (:wesj) from comment #1) > TBH, I intentionally wrote it this way originally because its super easy to > wrap in promises if you want: > > return new Promise(function(resolve, reject) { > sendMessageToJava(msg, resolve, reject); > }); > > but doesn't require them if you don't. I don't think it's quite that easy -- note that sendMessageToJava takes a single callback function, not two of them. For an example of how we currently have to wrap the API using promises, see http://mxr.mozilla.org/mozilla-central/source/mobile/android/base/tests/roboextender/testSelectionHandler.html?force=1#236. But why wouldn't you want them? Promises provide better built-in support for errors, so avoiding promises loses that advantage. In general, Mozilla APIs are slowly replacing the older callback-based methods with promise-based ones. Having promise-compatible APIs enable very elegant code. Consider: let fn = Task.async(function* () { let response = yield sendRequestToJava({ foo: bar }); console.log("got response: " + response); }); Currently, that would have to be written like this: let fn = Task.async(function* () { let response = yield new Promise(function (resolve, reject) { sendMessageToJava({ foo: bar }, function (res, err) { (err) ? reject(err) : resolve(res); }); }); console.log("got response: " + response); });
I've just forgotten how my api looked :) Its not hard enough to convert either way I guess: var send = function(msg, callback) { sendMessageToJava(msg).then(callback) .catch(callback.bind(this, null)); } We talked about this a bit. I don't have a strong preference against, and I don't think anyone on our team will fight it anymore either(?) so lets give it a whirl. If a callers really really really needs callbacks, they can write their own nsIAndroidBridge methods?
Drive-by request: Is Messaging.jsm something that we expect add-ons to use? If so, we should make an MDN article for Messaging.jsm, so that we can update it to talk about this change :)
Comment on attachment 8474672 [details] [diff] [review] Implement sendRequestToJava Review of attachment 8474672 [details] [diff] [review]: ----------------------------------------------------------------- ::: mobile/android/modules/Messaging.jsm @@ +5,5 @@ > > const { classes: Cc, interfaces: Ci, utils: Cu } = Components; > > Cu.import("resource://gre/modules/Services.jsm"); > +Cu.import("resource://gre/modules/Promise.jsm"); Do we need this? I thought promises were available in jsms now... @@ +23,5 @@ > + sendRequestToJava(aMessage) > + .then(response => aCallback(response, null)) > + .catch(response => aCallback(null, response)); > + } else { > + Services.androidBridge.handleGeckoMessage(aMessage); So this becomes the API if you don't want a response, and the other becomes the API if you do. That scares me a bit. It seems easy to get wrong. I wonder if we can pass a boolean or something to the other method... (I hate that idea too). @@ +30,5 @@ > + > +/** > + * Sends a message to Java, returning a promise that resolves to the response. > + */ > +function sendRequestToJava(aMessage) { I'd probably put this in your current RequestService @@ +54,5 @@ > aMessage.__guid__ = id; > Services.obs.addObserver(obs, aMessage.type + ":Response", false); > + }); > + > + Services.androidBridge.handleGeckoMessage(aMessage); I'd put this inside the promise, after the response observer was added. This seems like it could be racy here.
Comment on attachment 8474672 [details] [diff] [review] Implement sendRequestToJava Review of attachment 8474672 [details] [diff] [review]: ----------------------------------------------------------------- (In reply to Wesley Johnston (:wesj) from comment #7) > So this becomes the API if you don't want a response, and the other becomes > the API if you do. That scares me a bit. It seems easy to get wrong. I > wonder if we can pass a boolean or something to the other method... (I hate > that idea too). I suggested sendRequestForResponse in the other bug, since it kinda maps to Android's startActivityForResponse(). > I'd probably put this in your current RequestService I know you're using the other bug for this. I'm fine either way. I DO think the handleGeckoMessage call needs to be in the promise, so thats the r-. (But once its fixed I don't mind if you flip to r+)
Attachment #8474672 - Flags: review?(wjohnston) → review-
(In reply to Wesley Johnston (:wesj) from comment #8) > I DO think the handleGeckoMessage call needs to be in the promise It doesn't; the Promise spec says that the function given to Promise is executed immediately. But it works either way, so I'll move it there if you think it's clearer.
No longer blocks: 1043633
Depends on: 1043633
Updated for comments and rebased onto bug 1043633.
Attachment #8474672 - Attachment is obsolete: true
Updates remaining sendMessageToJava calls to use new API. Try push: https://tbpl.mozilla.org/?tree=Try&rev=e382e31a4600
Attachment #8479384 - Flags: review?(wjohnston)
Attachment #8479382 - Flags: review?(wjohnston)
Comment on attachment 8479382 [details] [diff] [review] Implement sendRequestForResult Review of attachment 8479382 [details] [diff] [review]: ----------------------------------------------------------------- ::: mobile/android/modules/Messaging.jsm @@ +9,2 @@ > Cu.import("resource://gre/modules/Task.jsm"); > +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Random move? @@ +20,5 @@ > > + if (aCallback) { > + Messaging.sendRequestForResult(aMessage) > + .then(result => aCallback(result, null), > + error => aCallback(null, error)); So pretty :)
Attachment #8479382 - Flags: review?(wjohnston) → review+
Comment on attachment 8479384 [details] [diff] [review] Change callback-based sendMessageToJava calls to Messaging.sendRequestForResult Review of attachment 8479384 [details] [diff] [review]: ----------------------------------------------------------------- Nice :) Try run?
Attachment #8479384 - Flags: review?(wjohnston) → review+
(In reply to Wesley Johnston (:wesj) from comment #13) > Nice :) Try run? Done (comment 11).
Status: NEW → RESOLVED
Closed: 11 years ago
Flags: in-testsuite+
Resolution: --- → FIXED
Target Milestone: --- → Firefox 35
Depends on: 1062622
Product: Firefox for Android → Firefox for Android Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: