异步监听器
Antora 会按照监听器的注册顺序同步调用它们。即使监听器使用 async
关键字标记为异步或监听器返回 Promise,情况也是如此。Antora 将等待监听器调用完成后再调用下一个监听器(因此也是在继续自己的操作之前)。这种行为与 Node.js 内置的 NodeEmitter 的行为不同。
将监听器标记为异步或返回 Promise 的好处是,监听器可以执行异步操作。当然,这些操作都将在 Antora 继续执行之前解决,因此它们将在函数边界之外以同步方式执行。
当程序调用 await 时,Promise 就结束了。显然,这一要求会一直影响到程序的顶层函数。Antora 允许您将扩展监听器定义为 async 或返回 Promise,从而隐藏了这一细节。
|
让我们来看一个从 URL 获取文件并发布到网站的例子。
Example 1. fetch-and-publish-readme-extension.js
module.exports.register = function () {
this.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' } })
})
}
请注意,我们在监听器函数中添加了 async
关键字。这样,我们就可以在函数内部使用 await
关键字。
作为练习,你可以尝试从每个内容源的每个分支检索一个文件,并将其添加到已发布的网站。为了给你一个提示,你需要访问 playbook
变量来获取内容源列表。
如果不想让 Antora 等待异步监听器的完成,可以返回一个空的承诺(例如,return Promise.resolve()
),或者从监听器中移除 async
关键字。不过,如果这样做,就需要添加一个监听器来监听生成器中稍后触发的事件(如 contextClosed
),这样就可以在 Antora 完成之前解析承诺。
让我们来看看与前面相同的示例,只不过它是在生成网站的同时在后台下载 README.adoc。为了帮助管理悬而未决的承诺状态,我们还将其重写为 基于类的扩展。
Example 2. background-fetch-and-publish-readme-extension.js
const https = require('https')
class FetchAndPublishReadmeExtension {
static register ({ config }) {
return new FetchAndPublishReadmeExtension(this, config)
}
constructor (context, config) {
;(this.context = context)
.on('playbookBuilt', this.onPlaybookBuilt.bind(this))
.on('beforePublish', this.onBeforePublish.bind(this))
this.readmeUrl = config.readmeUrl || 'https://gitlab.com/antora/antora/-/raw/HEAD/README.adoc'
this.contentsPromise = undefined
}
playbookBuilt ({ siteCatalog }) {
this.contentsPromise = new Promise((resolve, reject) => {
const buffer = []
https
.get(this.readmeUrl, (response) => {
response.on('data', (chunk) => buffer.push(chunk.toString()))
response.on('end', () => resolve(buffer.join('').trimRight()))
})
.on('error', reject)
})
}
async onBeforePublish ({ siteCatalog }) {
const contents = await this.contentsPromise
siteCatalog.addFile({ contents: Buffer.from(contents), out: { path: 'README.adoc' } })
}
}
module.exports = FetchAndPublishReadmeExtension
请注意,只有 onBeforePublish
监听器函数是异步的,因此它可以等待 onPlaybookBuilt
监听器函数启动的承诺。现在,扩展还接受 README 的 URL 作为名为 readme_url
的配置键。