title: Why MessageChannel blocks forever and the client never gets message?
body: <p>I have a problem where my <code>MessageChannel</code> does not send a message from a service worker to a client. Why MessageChannel blocks forever and the client never gets message?</p>
  
  <p>In the sw on <code>fetch</code> event I create a <code>MessageChannel</code> then I do <code>postMessage</code>, however the client never gets <code>addEventListener('message'</code> fired why ?</p>
  
  <p>For service worker I created method like that:</p>
  
  <pre><code>self.addEventListener("fetch", async (event) =&gt; {
    // Exit early if we don't have access to the client.
    // Eg, if it's cross-origin.
    if (!event.clientId) return null;
  
    // eslint-disable-next-line
    const client = await clients.get(event.clientId);
    const response = await sendMessageToClient(client, { url: event.request.url }, 5000);
  })
  
  async function sendMessageToClient(client, message, timeoutAfter) {
    // Exit early if we don't get the client.
    // Eg, if it closed.
    if (!client) return null;
  
    // This wraps the message posting/response in a promise, which will resolve if the response doesn't
    // contain an error, and reject with the error if it does.
    return await new Promise((resolve, reject) =&gt; {
      const messageChannel = new MessageChannel();
      messageChannel.port1.onmessage = function (event) {
        if (event.data &amp;&amp; event.data.error) {
          reject(event.data.error);
        } else {
          resolve(event.data);
        }
      };
  
      // This sends the message data as well as transferring messageChannel.port2 to the client.
      // The client can then use the transferred port to reply via postMessage(), which
      // will in turn trigger the onmessage handler on messageChannel.port1.
      // See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
      client.postMessage(message, [messageChannel.port2]);
  
      // Set up the timeout
      setTimeout(() =&gt; {
        messageChannel.port1.close();
        messageChannel.port2.close();
  
        reject('Promise timed out after ' + timeoutAfter + ' ms');
  
      }, timeoutAfter);
    });
  }
  </code></pre>
  
  <p>On the client I expect to get message here:</p>
  
  <pre><code>// Set up a listener for messages posted from the service worker.
  // The service worker is set to post a message to specific client only
  // so you should see this message event fire once.
  // You can force it to fire again by visiting this page in an Incognito window.
  navigator.serviceWorker.addEventListener('message', function (event) {
    console.log(event.data);
  });
  </code></pre>
  
  <p>But I never get the message on client and if there is no time out it will w8 forever.</p>
  
  <h1>Update</h1>
  
  <p>what i have tried:</p>
  
  <pre><code>  window.addEventListener('message', function (event) { console.log('window.addEventListener', event.data) });
    window.onmessage = function (event) { console.log('window.onmessage', event.data) };
    navigator.serviceWorker.addEventListener('message', function (event) { console.log('navigator.serviceWorker.addEventListener', event.data) });
    navigator.serviceWorker.onmessage = function (event) { console.log('navigator.serviceWorker.onmessage', event.data) };
    // navigator.serviceWorker.controller.addEventListener('message', function (event) { console.log('navigator.serviceWorker.contoller.addEventListener', event.data) });
    // navigator.serviceWorker.controller.onmessage = function (event) { console.log('navigator.serviceWorker.contoller.onmessage', event.data) };
    navigator.serviceWorker.ready.then(function (registration) {
      console.log('navigator.serviceWorker.ready');
      registration.active.addEventListener('message', function (event) { console.log('registration.active.addEventListener', event.data) });
      registration.active.onmessage = function (event) { console.log('registration.active.onmessage', event.data) };
    });
  
    navigator.serviceWorker.register("sw.js")
      .then(function (registration) {
        // Registration was successful
        console.log("ServiceWorker registration successful with scope: ", registration.scope);
      })
      .catch(function (error) {
        console.error("Service Worker Error", error);
      });
  }
  </code></pre>
  
  <p>and the only logs I got were:</p>
  
  <blockquote>
    <p>Navigated to <a href="http://localhost:3000/" rel="nofollow noreferrer">http://localhost:3000/</a> navigator.serviceWorker.ready</p>
    
    <p>ServiceWorker registration successful with scope: </p>
    
    <p><a href="http://localhost:3000/" rel="nofollow noreferrer">http://localhost:3000/</a></p>
  </blockquote>