Worker unexpected async deadlock

Hi, the documentation says that async element(element) handlers should be able to make subrequests in parallel and that the parser will go back and fulfill them when they succeed, but I’m seeing that async handlers are run serially.

Here is a minimal test case I have put together to illustrate the kind of task I would like to accomplish:

PAGE_BODY = 
`<html>
<head>
  <title>My Site</title>
  <meta name="description" value="A website" />
</head>
<body>
  <h1>Welcome to the internet</h1>
  <script defer src="https://example.com/javascript.js" />
</html>
`

addEventListener("fetch", (event) => {
  event.respondWith(
    handleRequest(event.request).catch(
      (err) => new Response(err.stack, { status: 500 })
    )
  );
});

class ScriptFoldHandler {

  constructor(nonce) {
    this.nonce = nonce
    //
    this.aboveFoldScripts = []
    this.aboveFoldReady = new Promise((resolve, reject) => {
      this.resolveAboveFoldScripts = resolve
    })
    console.trace('constructor')
  }

  async element(element) {
    console.trace('element')
    if (element.tagName === 'title') {
      console.trace('element')
      await this.aboveFoldReady
      console.trace('element')
      this.aboveFoldScripts.forEach(script => {
        console.trace('element:forEach')
        element.after(`<script defer="defer" nonce="${nonce}" src="${script}"></script>`, { html: true })
      })
    } else if (element.tagName === 'script') {
      console.trace('element')
      const type = element.getAttribute('type')
      if (type && type !== 'text/javascript')
        return
      this.aboveFoldScripts.push(element.getAttribute('src'))
    }
  }

  end(end) {
    console.trace('end')
    this.resolveAboveFoldScripts()
  }
}

/**
 * Many more examples available at:
 *   https://developers.cloudflare.com/workers/examples
 * @param {Request} request
 * @returns {Promise<Response>}
 */
async function handleRequest(request) {
  const ScriptFoldHandler_ = new ScriptFoldHandler('nonce')

  const rewriter = new HTMLRewriter()
    .on('title', ScriptFoldHandler_)
    .on('script[src]', ScriptFoldHandler_)
    .onDocument(ScriptFoldHandler_)

  const { pathname } = new URL(request.url);

  return rewriter.transform(new Response(PAGE_BODY))
}

You can test it on https://workers.new .

It results in the following output:

worker.js:30 constructor
worker.js:34 element
worker.js:36 element
A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from JavaScript to resolve, but has detected that the Promise cannot possibly ever resolve because all code and events related to the Promise's request context have already finished.
Uncaught (in response) Error: The script will never generate a response.
Script modified; context reset.

Can anyone comment on why the deadlock or suggest another way to scrape elements further in the stream (i.e. below the ) and insert them into a specific place in the ?

I can’t edit, but this sentence was supposed to read: “scrape elements further in the stream (i.e. below the BODY) and insert into a specific place in the HEAD?”