Open
Bug 1035579
Opened 10 years ago
Updated 2 years ago
sendAsyncMessage callback
Categories
(Core :: DOM: Core & HTML, defect)
Tracking
()
UNCONFIRMED
People
(Reporter: noitidart, Unassigned)
Details
User Agent: Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0 (Beta/Release) Build ID: 20140703154127 Steps to reproduce: I used the message manager api to. I used the sendAsyncMessage call back instead of sendSyncMessage because async is always preferred. However with sendAsyncMessage I cannot supply a callback. Please add callback feature to sendAsyncMessage. This stackoverflow topic explains more in detail please: http://stackoverflow.com/questions/24619104/message-manager-api-sendasyncmessage-callback Expected results: please create callback feature
Updated•10 years ago
|
Component: Untriaged → DOM
Product: Firefox → Core
Comment 1•10 years ago
|
||
When would you expect the callback to fire? Why not just send a return asynchronous message from the parent?
Yeah sending the return async message is how I'm having to do it. But it requires a two step setup thats not necessarily related. Just thought to make it work like callbacks as arguments to a function usually work. I tried to figure it out and evnetually posted on stackoverflow and was told its not available. So people might waste time trying to force figure it out, to realize its not there. People will try to figure it out because I think they expect it. At least I did, and i work with callbacks a bit.
Reason I would like this is because it matches promise logic. Just like PromiseWorker.jsm: http://mxr.mozilla.org/mozilla-release/source/toolkit/components/osfile/modules/osfile_async_front.jsm#332 332 let promise = this._worker.post(...message); 333 334 // Wait for result Would be awesome if we can get this.
because sendAsyncMessage is going to be so widely used. Its not like ChromeWorker's and postMessage, people writing ChromeWorkers definitely have a higher then average skill level. And sendAsyncMessage will definitely be used by new comers. We need a sendAsyncMessageWithCallback I wrote this postMessageWithCallback for ChromeWorker, its very simple and crude, but i doubt your average coder will do that, but will definitely definitely look for that with the sendAsyncMessage
Comment 5•9 years ago
|
||
We don't need sendAsyndMessageWithCallback but I can see it being quite useful. I need to get back to bug 888600 soon, and after that fixing this should be somewhat simpler.
Thanks Olli. All of google chrome stuff offers with callback, so noobs definitely get it. Its hard for them to set up callback communication but simple for more experienced people. i set up postMessageWithCallback here: https://github.com/Noitidart/IdleStateLocked/blob/master/bootstrap.js#L73
(In reply to Olli Pettay [:smaug] from comment #5) > We don't need sendAsyndMessageWithCallback but I can see it being quite > useful. > > I need to get back to bug 888600 soon, and after that fixing this should be > somewhat simpler. Hi there Olli I was wondering if you had any update on this? Users are trying to write their own versions: http://stackoverflow.com/a/31073360/1828637
Flags: needinfo?(bugs)
Comment 8•9 years ago
|
||
Don't have updates as of now, sorry. Of course one can always write a small js wrapper on top of sendAsyncMessage to deal with this kind of stuff.
Flags: needinfo?(bugs)
(In reply to Olli Pettay [:smaug] from comment #8) > Don't have updates as of now, sorry. > > Of course one can always write a small js wrapper on top of sendAsyncMessage > to deal with > this kind of stuff. Oh no problem no sorries please thanks for your hard work. Thanks for fast reply :)
Reporter | ||
Comment 10•9 years ago
|
||
I hooked one up that allows setting up callback on both sides. I call it the sendAsyncMessageWithCallback But the listener is modified so that it calls a function with the first element in the array. Its probably not as simple as we want for production. I'm used to PromiseWorker so I like being able to send to my functions multiple arguments, so if we land this we should probably do it like Promise.resolve, allow only one argument (and devusers can just make that an object with multiple fields if they need multiple arguments). I found its important to set up return array or promise. Because what if one side is doing async stuff, so this works pretty good. ///////////// parentscript side (ie: bootstrap) const SAM_CB_PREFIX = '_sam_gen_cb_'; function sendAsyncMessageWithCallback(aMessageManager, aGroupId, aMessageArr, aCallbackScope, aCallback) { var thisCallbackId = SAM_CB_PREFIX + new Date().getTime(); aCallbackScope = aCallbackScope ? aCallbackScope : bootstrap; aCallbackScope[thisCallbackId] = function(aMessageArr) { delete aCallbackScope[thisCallbackId]; aCallback.apply(null, aMessageArr); } aMessageArr.push(thisCallbackId); aMessageManager.sendAsyncMessage(aGroupId, aMessageArr); } var listener = { // framescript msg listener funcScope: myFuncstionsObj, receiveMessage: function(aMsgEvent) { var aMsgEventData = aMsgEvent.data; console.log('ICGenWorkerFuncs.fwInstances[aId] getting aMsgEventData:', aMsgEventData); // aMsgEvent.data should be an array, with first item being the unfction name in bootstrapCallbacks var callbackPendingId; if (typeof aMsgEventData[aMsgEventData.length-1] == 'string' && aMsgEventData[aMsgEventData.length-1].indexOf(SAM_CB_PREFIX) == 0) { callbackPendingId = aMsgEventData.pop(); } aMsgEventData.push(aMsgEvent); // this is special for server side, so the function can do aMsgEvent.target.messageManager to send a response var funcName = aMsgEventData.shift(); if (funcName in this.funcScope) { var rez_parentscript_call = this.funcScope[funcName].apply(null, aMsgEventData); if (callbackPendingId) { // rez_parentscript_call must be an array or promise that resolves with an array if (rez_parentscript_call.constructor.name == 'Promise') { rez_parentscript_call.then( function(aVal) { // aVal must be an array aMsgEvent.target.messageManager.sendAsyncMessage(core.addon.id, [callbackPendingId, aVal]); }, function(aReason) { aMsgEvent.target.messageManager.sendAsyncMessage(core.addon.id, [callbackPendingId, ['promise_rejected', aReason]]); } ).catch( function(aCatch) { aMsgEvent.target.messageManager.sendAsyncMessage(core.addon.id, [callbackPendingId, ['promise_rejected', aReason]]); } ); } else { // assume array aMsgEvent.target.messageManager.sendAsyncMessage(core.addon.id, [callbackPendingId, rez_parentscript_call]); } } } else { console.warn('funcName', funcName, 'not in scope of this.funcScope') } // else is intentionally on same line with console. so on finde replace all console. lines on release it will take this out } }; Services.mm.addMessageListener(core.addon.id, listener); //////////////////// framescript side const SAM_CB_PREFIX = '_sam_gen_cb_'; function sendAsyncMessageWithCallback(aMessageManager, aGroupId, aMessageArr, aCallbackScope, aCallback) { var thisCallbackId = SAM_CB_PREFIX + new Date().getTime(); aCallbackScope = aCallbackScope ? aCallbackScope : bootstrap; // todo: figure out how to get global scope here, as bootstrap is undefined aCallbackScope[thisCallbackId] = function(aMessageArr) { delete aCallbackScope[thisCallbackId]; aCallback.apply(null, aMessageArr); } aMessageArr.push(thisCallbackId); aMessageManager.sendAsyncMessage(aGroupId, aMessageArr); } var bootstrapMsgListener = { funcScope: bootstrapCallbacks, receiveMessage: function(aMsgEvent) { var aMsgEventData = aMsgEvent.data; console.log('framescript getting aMsgEvent:', aMsgEventData); // aMsgEvent.data should be an array, with first item being the unfction name in this.funcScope var callbackPendingId; if (typeof aMsgEventData[aMsgEventData.length-1] == 'string' && aMsgEventData[aMsgEventData.length-1].indexOf(SAM_CB_PREFIX) == 0) { callbackPendingId = aMsgEventData.pop(); } var funcName = aMsgEventData.shift(); if (funcName in this.funcScope) { var rez_fs_call = this.funcScope[funcName].apply(null, aMsgEventData); if (callbackPendingId) { // rez_fs_call must be an array or promise that resolves with an array if (rez_fs_call.constructor.name == 'Promise') { rez_fs_call.then( function(aVal) { // aVal must be an array contentMMFromContentWindow_Method2(content).sendAsyncMessage(core.addon.id, [callbackPendingId, aVal]); }, function(aReason) { contentMMFromContentWindow_Method2(content).sendAsyncMessage(core.addon.id, [callbackPendingId, ['promise_rejected', aReason]]); } ).catch( function(aCatch) { contentMMFromContentWindow_Method2(content).sendAsyncMessage(core.addon.id, [callbackPendingId, ['promise_rejected', aReason]]); } ); } else { // assume array contentMMFromContentWindow_Method2(content).sendAsyncMessage(core.addon.id, [callbackPendingId, rez_fs_call]); } } } else { console.warn('funcName', funcName, 'not in scope of this.funcScope') } // else is intentionally on same line with console. so on finde replace all console. lines on release it will take this out } }; contentMMFromContentWindow_Method2(content).addMessageListener(core.addon.id, bootstrapMsgListener); ///////////////////////////////// EXAMPLE USAGE // framescript side sendAsyncMessageWithCallback(contentMMFromContentWindow_Method2(content), core.addon.id, ['testSettingCbInFramescript', 'ARG1'], bootstrapMsgListener.funcScope, function(aRetArg1){ console.log('back in framescript side callback aRetArg1:', aRetArg1); }); ///// parentscript side var callbacks = { testSettingCbInFramescript: function(arg1) { console.log('in testSettingCbInFramescript on parentscript side, arg1:', arg1); return ['parentscript testSettingCbInFramescript returning THISSSS']; } } ///////////////////////////////// EXAMPLE USAGE - setting up callback in parent script - opposite of above ///// parentscript side ///// framescript side
Assignee | ||
Updated•5 years ago
|
Component: DOM → DOM: Core & HTML
Updated•2 years ago
|
Severity: normal → S3
You need to log in
before you can comment on or make changes to this bug.
Description
•