|
21 | 21 | let unsuspend = result => { |
22 | 22 | pending.delete(id); |
23 | 23 | if (wrapper.unsuspend) { |
24 | | - setTimeout(wrapper.unsuspend, 0); |
| 24 | + wrapper.unsuspend(); |
25 | 25 | } |
26 | 26 | return result; |
27 | 27 | } |
|
31 | 31 | unsuspend(); |
32 | 32 | throw e; |
33 | 33 | } |
34 | | - console.debug("sendSyncMessage: returning", result); |
| 34 | + /* |
| 35 | + // Uncomment me to add artificial delay for debugging purposes |
| 36 | + let tmpResult = result; |
| 37 | + result = new Promise(resolve => setTimeout(() => resolve(tmpResult), 500)); |
| 38 | + */ |
35 | 39 | return (result instanceof Promise ? result |
36 | 40 | : new Promise(resolve => resolve(result)) |
37 | 41 | ).then(result => unsuspend(result)); |
|
61 | 65 | let wrapper = pending.get(msgId); |
62 | 66 | if (!wrapper.unsuspend) { |
63 | 67 | wrapper.unsuspend = resolve; |
64 | | - return; |
65 | 68 | } else { |
66 | 69 | let {unsuspend} = wrapper; |
67 | 70 | wrapper.unsuspend = () => { |
68 | 71 | unsuspend(); |
69 | 72 | resolve(); |
70 | 73 | } |
71 | 74 | } |
| 75 | + return; |
72 | 76 | } |
73 | 77 | resolve(); |
74 | 78 | }).then(() => ret("go on")) |
|
201 | 205 | let uuid = () => (Math.random() * Date.now()).toString(16); |
202 | 206 | let docUrl = document.URL; |
203 | 207 | browser.runtime.sendSyncMessage = (msg, callback) => { |
204 | | - // we interrogate the canScript() callback to know whether the caller |
205 | | - // wants scripts deferred by sendSyncMessage to be eventually executed: |
206 | | - // - undefined -> too soon to tell, suspend |
207 | | - // - true -> go on and execute |
208 | | - // - false -> block |
209 | | - let canScript; |
210 | | - if (callback && typeof callback === "object") { |
211 | | - ({canScript, callback} = callback); |
212 | | - } |
213 | | - if (typeof canScript !== "function") { |
214 | | - // if no canScript() callback was passed, default to execute scripts |
215 | | - canScript = () => true; |
216 | | - } |
217 | | - |
218 | 208 | let msgId = `${uuid()},${docUrl}`; |
219 | 209 | let url = `${ENDPOINT_PREFIX}id=${encodeURIComponent(msgId)}` + |
220 | 210 | `&url=${encodeURIComponent(docUrl)}`; |
|
225 | 215 | } |
226 | 216 |
|
227 | 217 | if (MOZILLA) { |
| 218 | + |
228 | 219 | // In order to cope with inconsistencies in XHR synchronicity, |
229 | 220 | // allowing scripts to be executed (especially with synchronous loads |
230 | 221 | // or when other extensions manipulate the DOM early) we additionally |
231 | 222 | // suspend on beforescriptexecute events |
232 | 223 |
|
233 | 224 | let suspendURL = url + "&suspend=true"; |
234 | 225 | let suspended = 0; |
| 226 | + let suspendedId = 0; |
235 | 227 | let suspend = () => { |
236 | 228 | suspended++; |
237 | | - console.debug("Suspended, count:", suspended) |
| 229 | + let id = suspendedId++; |
| 230 | + console.debug("sendSyncMessage suspend #%s/%s", id, suspended); |
238 | 231 | try { |
239 | 232 | let r = new XMLHttpRequest(); |
240 | 233 | r.open("GET", suspendURL, false); |
|
243 | 236 | console.error(e); |
244 | 237 | } |
245 | 238 | suspended--; |
246 | | - console.debug("Unsuspended, count: ", suspended); |
| 239 | + console.debug("sendSyncMessage resume #%s/%s", id, suspended); |
247 | 240 | }; |
248 | 241 |
|
249 | | - let onBeforeScript = e => { |
250 | | - if(typeof canScript() === "undefined") { |
251 | | - suspend(); |
252 | | - } |
253 | | - let allowed = canScript(); |
254 | | - if (typeof allowed === "undefined") { |
255 | | - console.error("sendSyncMessage: script unsuspended before canScript() is defined!", e.target); |
256 | | - } |
257 | | - if (!allowed) { |
258 | | - console.debug("sendSyncMessage blocked a script element", e.target); |
259 | | - e.preventDefault(); |
260 | | - } |
261 | | - }; |
262 | 242 |
|
263 | | - addEventListener("beforescriptexecute", onBeforeScript, true); |
| 243 | + |
264 | 244 | let domSuspender = new MutationObserver(records => { |
| 245 | + console.debug("sendSyncMessage suspending on ", records) |
265 | 246 | suspend(); |
266 | 247 | }); |
267 | 248 | domSuspender.observe(document.documentElement, {childList: true}); |
268 | 249 |
|
269 | 250 |
|
270 | | - |
271 | 251 | let finalize = () => { |
| 252 | + console.debug("sendSyncMessage finalizing"); |
272 | 253 | domSuspender.disconnect(); |
273 | | - removeEventListener("beforescriptexecute", onBeforeScript, true); |
274 | 254 | }; |
275 | 255 |
|
276 | 256 | // on Firefox we first need to send an async message telling the |
277 | 257 | // background script about the tab ID, which does not get sent |
278 | 258 | // with "privileged" XHR |
279 | 259 | let result; |
| 260 | + |
280 | 261 | browser.runtime.sendMessage( |
281 | 262 | {__syncMessage__: {id: msgId, payload: msg}} |
282 | 263 | ).then(r => { |
283 | 264 | result = r; |
284 | 265 | if (callback) callback(r); |
| 266 | + finalize(); |
285 | 267 | }).catch(e => { |
286 | 268 | throw e; |
287 | 269 | }); |
288 | 270 |
|
289 | | - |
290 | | - |
291 | | - if (callback) { |
292 | | - let realCB = callback; |
293 | | - callback = r => { |
294 | | - try { |
295 | | - realCB(r); |
296 | | - } finally { |
297 | | - finalize(); |
298 | | - } |
299 | | - }; |
300 | | - return; |
301 | | - } |
302 | | - |
303 | 271 | try { |
304 | 272 | suspend(); |
305 | 273 | } finally { |
|
0 commit comments