Asynchronous Listeners

Antora calls listeners synchronously in the order they’re registered. This is true even if a listener is marked as asynchronous using the async keyword or by returning a Promise (which differs from the behavior of the built-in NodeEmitter in Node.js). Antora will await the completion of the listener invocation before calling the next listener (and thus before continuing its own operation).

The benefit of marking a listener as async, or returning a Promise, is that the listener can, itself, perform asynchronous operations. Of course, these operations will all be resolved before Antora proceeds, so they are made to behave in a synchronous fashion outside the boundaries of the function.

Let’s look at an example of fetching a file from a URL and publishing it to the site.

Example 1. fetch-and-publish-readme-extension.js
module.exports.register = (pipeline) => {
  pipeline.on('beforePublish', async ({ siteCatalog }) => {
    const https = require('https')
    const contents = await new Promise((resolve, reject) => {
      const buffer = []
      https.get('https://gitlab.com/antora/antora/-/raw/HEAD/README.adoc', (response) => {
        response.on('data', (chunk) => buffer.push(chunk.toString()))
        response.on('end', () => resolve(buffer.join('').trimRight()))
      }).on('error', reject)
    })
    siteCatalog.addFile({ contents: Buffer.from(contents), out: { path: 'README.adoc' } })
  })
}

Notice that we have added the async keyword to the listener function. This allows us to the use the await keyword inside the function.

As an exercise, you could try retrieving a file from each branch of each content source and adding it to the published site. To give you a hint, you would need to access the playbook variable to get a list of content sources.

If you don’t want Antora to wait for the completion of your asynchronous listener, you can either return an empty promise (e.g, return Promise.resolve()), or you can remove the async keyword from your listener. However, if you do so, you’ll need to add a listener that listens for an event later in the pipeline, such as sitePublished, so that you can resolve the promise before Antora completes.