@@ -18,7 +18,7 @@ type MessageFromWorker = {
1818 type : 'onmessage' | 'onerror' | 'onmessageerror' ;
1919 message : any ;
2020} ;
21- export type MessageFromIframe = { type : 'iframe-ready' } | MessageFromWorker ;
21+ export type MessageFromIframe = { type : 'iframe-ready' } | { type : 'worker-ready' } | MessageFromWorker ;
2222export type MessageToIframe = { type : 'terminate' } | { type : 'init-worker' ; code : string } | { type : 'postMessage' ; message : any } ;
2323
2424/**
@@ -29,16 +29,19 @@ export type MessageToIframe = { type: 'terminate' } | { type: 'init-worker'; cod
2929 * The iframe used for sandboxing must follow a specific contract. It:
3030 * 1. Must send a ready message to the main-thread.
3131 * 2. Must listen for a message from main-thread with the code to initialize a Worker with.
32- * 3. Must proxy all messages between the Worker and Parent, including errors.
32+ * 3. Must send "worker-ready" once worker is initialized.
33+ * 4. Must proxy all messages between the Worker and Parent, including errors.
3334 */
3435class IframeWorker {
3536 // Public Worker API
3637 public onerror : ( this : IframeWorker , ev : ErrorEvent ) => any ;
3738 public onmessage : ( this : IframeWorker , ev : MessageEvent ) => any ;
3839 public onmessageerror : ( this : IframeWorker , ev : MessageEvent ) => any ;
40+ public readyPromise : Promise < void > ;
3941
4042 // Internal variables.
4143 private iframe : HTMLIFrameElement ;
44+ private readyPromiseResolve : Function ;
4245
4346 /**
4447 * @param url The URL to initiate the worker from.
@@ -50,6 +53,9 @@ class IframeWorker {
5053 this . iframe . setAttribute ( 'style' , 'display:none' ) ;
5154 this . iframe . setAttribute ( 'src' , iframeUrl ) ;
5255 this . url = url ;
56+ this . readyPromise = new Promise ( ( resolve ) => {
57+ this . readyPromiseResolve = resolve ;
58+ } ) ;
5359
5460 this . setupInit ( ) ;
5561 this . proxyFromWorker ( ) ;
@@ -65,11 +71,14 @@ class IframeWorker {
6571 fetch ( this . url . toString ( ) )
6672 . then ( ( res ) => res . text ( ) )
6773 . then ( ( code ) => {
68- if ( ( event . data as MessageFromIframe ) . type == 'iframe-ready' ) {
74+ const data = event . data as MessageFromIframe ;
75+ if ( data . type == 'iframe-ready' ) {
6976 const msg : MessageToIframe = { type : 'init-worker' , code } ;
7077 this . iframe . contentWindow ! . postMessage ( msg , '*' ) ;
78+ } else if ( data . type === 'worker-ready' ) {
79+ this . readyPromiseResolve ( ) ;
80+ window . removeEventListener ( 'message' , listener ) ;
7181 }
72- window . removeEventListener ( 'message' , listener ) ;
7382 } ) ;
7483 } ;
7584 window . addEventListener ( 'message' , listener ) ;
@@ -99,7 +108,9 @@ class IframeWorker {
99108 */
100109 postMessage ( message : any , transferables ?: Array < Transferable > ) {
101110 const msg : MessageToIframe = { type : 'postMessage' , message } ;
102- this . iframe . contentWindow ! . postMessage ( msg , '*' , transferables ) ;
111+ this . readyPromise . then ( ( ) => {
112+ this . iframe . contentWindow ! . postMessage ( msg , '*' , transferables ) ;
113+ } ) ;
103114 }
104115
105116 /**
0 commit comments