函数
页面摘要:
src/index包含全局的 register、bootstrap 和 destroy 函数,用于在应用程序生命周期内运行逻辑。
./src/index.js 文件(在基于 TypeScript的项目中为 ./src/index.ts 文件)包含全局的 register、bootstrap 和 destroy 函数,可用于添加动态且基于逻辑的配置。
这些函数可以是同步的、异步的,或返回一个 Promise。

可用模式
生命周期函数支持 3 种执行模式/方式,以便你将其与它们所管理的依赖项对齐。Strapi 会等待每个函数完成——无论是正常返回、解析一个 async 函数,还是解析一个 Promise——然后才会继续启动或关闭。
返回值不会被 Strapi 使用,因此函数应在其设置或清理完成时解析(或返回),并通过抛出错误或拒绝来表明失败。
同步
同步函数运行会立即完成、无需等待其他异步任务的逻辑。
JavaScript
module.exports = {
register({ strapi }) {
strapi.log.info('Registering static configuration');
},
bootstrap({ strapi }) {
strapi.log.info('Bootstrap finished without awaiting tasks');
},
destroy({ strapi }) {
strapi.log.info('Server shutdown started');
}
};
TypeScript
export default {
register({ strapi }) {
strapi.log.info('Registering static configuration');
},
bootstrap({ strapi }) {
strapi.log.info('Bootstrap finished without awaiting tasks');
},
destroy({ strapi }) {
strapi.log.info('Server shutdown started');
}
};
异步
异步函数使用 async 关键字来 await 任务(例如 API 调用或数据库查询),然后 Strapi 才继续。
JavaScript
module.exports = {
async register({ strapi }) {
await new Promise((resolve) => setTimeout(resolve, 200));
strapi.log.info('Async register finished after a short delay');
},
async bootstrap({ strapi }) {
const articles = await strapi
.documents('api::article.article')
.findMany({
status: 'published',
fields: ['documentId'],
});
strapi.log.info(`Indexed ${articles.length} published articles`);
},
async destroy({ strapi }) {
const cachedEntries = await strapi
.documents('api::temporary-cache.temporary-cache')
.findMany({ fields: ['documentId'] });
for (const { documentId } of cachedEntries) {
await strapi
.documents('api::temporary-cache.temporary-cache')
.delete({ documentId });
}
}
};
TypeScript
export default {
async register({ strapi }) {
await new Promise((resolve) => setTimeout(resolve, 200));
strapi.log.info('Async register finished after a short delay');
},
async bootstrap({ strapi }) {
const articles = await strapi
.documents('api::article.article')
.findMany({
status: 'published',
fields: ['documentId'],
});
strapi.log.info(`Indexed ${articles.length} published articles`);
},
async destroy({ strapi }) {
const cachedEntries = await strapi
.documents('api::temporary-cache.temporary-cache')
.findMany({ fields: ['documentId'] });
for (const { documentId } of cachedEntries) {
await strapi
.documents('api::temporary-cache.temporary-cache')
.delete({ documentId });
}
}
};
返回一个 Promise
返回 Promise 的函数会交还一个 Promise,以便 Strapi 可以等待其解析后再继续。
JavaScript
module.exports = {
register({ strapi }) {
return new Promise((resolve) => {
strapi.log.info('Registering with a delayed startup task');
setTimeout(resolve, 200);
});
},
bootstrap({ strapi }) {
return new Promise((resolve, reject) => {
strapi
.documents('api::category.category')
.findMany({ filters: { slug: 'general' }, pageSize: 1 })
.then((categories) => {
if (categories.length === 0) {
return strapi.documents('api::category.category').create({
data: { name: 'General', slug: 'general' },
});
}
return categories[0];
})
.then(() => {
strapi.log.info('Ensured default category exists');
resolve();
})
.catch(reject);
});
},
destroy({ strapi }) {
return new Promise((resolve, reject) => {
strapi
.documents('api::temporary-cache.temporary-cache')
.findMany({ fields: ['documentId'] })
.then((cachedEntries) =>
Promise.all(
cachedEntries.map(({ documentId }) =>
strapi
.documents('api::temporary-cache.temporary-cache')
.delete({ documentId })
)
)
)
.then(() => {
strapi.log.info('Cleared temporary cache before shutdown');
resolve();
})
.catch(reject);
});
}
};
TypeScript
export default {
register({ strapi }) {
return new Promise((resolve) => {
strapi.log.info('Registering with a delayed startup task');
setTimeout(resolve, 200);
});
},
bootstrap({ strapi }) {
return new Promise<void>((resolve, reject) => {
strapi
.documents('api::category.category')
.findMany({ filters: { slug: 'general' }, pageSize: 1 })
.then((categories) => {
if (categories.length === 0) {
return strapi.documents('api::category.category').create({
data: { name: 'General', slug: 'general' },
});
}
return categories[0];
})
.then(() => {
strapi.log.info('Ensured default category exists');
resolve();
})
.catch(reject);
});
},
destroy({ strapi }) {
return new Promise<void>((resolve, reject) => {
strapi
.documents('api::temporary-cache.temporary-cache')
.findMany({ fields: ['documentId'] })
.then((cachedEntries) =>
Promise.all(
cachedEntries.map(({ documentId }) =>
strapi
.documents('api::temporary-cache.temporary-cache')
.delete({ documentId })
)
)
)
.then(() => {
strapi.log.info('Cleared temporary cache before shutdown');
resolve();
})
.catch(reject);
});
}
};
生命周期函数
生命周期函数让你能够在 Strapi 启动和关闭的特定阶段放置代码。
register()函数用于服务启动前的配置期设置。bootstrap()函数用于需要 Strapi API 的初始化。destroy()函数用于应用程序停止时的拆卸。
Register
register 生命周期函数位于 ./src/index.js(或 ./src/index.ts)中,是一个在应用程序初始化之前运行的异步函数。
register() 是 Strapi 应用程序启动时发生的第一件事。这发生在任何设置过程_之前_,你在 register() 函数内无法访问数据库、路由、策略或任何其他后端服务器元素。
register() 函数可用于:
- 扩展插件
- 以编程方式扩展内容类型
- 加载一些环境变量
- 注册一个仅由当前 Strapi 应用程序使用的自定义字段,
- 注册一个用户与权限插件的自定义提供方。
更具体地说,register() 的典型用例包括前置安全任务,例如加载密钥、轮换 API 密钥,或在应用完成初始化之前注册身份验证提供方。
JavaScript
module.exports = {
register({ strapi }) {
strapi.customFields.register({
name: 'color',
plugin: 'my-color-picker',
type: 'string',
});
},
};
TypeScript
export default {
register({ strapi }) {
strapi.customFields.register({
name: 'color',
plugin: 'my-color-picker',
type: 'string',
});
},
};
Bootstrap
bootstrap 生命周期函数位于 ./src/index.js(或 ./src/index.ts)中,在每次服务器启动时都会被调用。
bootstrap() 在后端服务器启动_之前_、但在 Strapi 应用程序完成设置_之后_运行,因此你可以访问 strapi 对象中的任何内容。
bootstrap 函数可用于:
- 如果不存在管理员用户则创建一个
- 用一些必要数据填充数据库
- 为基于角色的访问控制(RBAC)功能声明自定义条件
更具体地说,bootstrap() 的一个典型用例是支持编辑工作流。例如在启动时植入起始内容、附加 Webhook 或调度定时任务。
你可以在终端中运行 yarn strapi console(或 npm run strapi console)并与 strapi 对象进行交互。
JavaScript
module.exports = {
async bootstrap({ strapi }) {
const categories = await strapi
.documents('api::category.category')
.findMany({ filters: { slug: 'general' }, pageSize: 1 });
if (categories.length === 0) {
await strapi.documents('api::category.category').create({
data: { name: 'General', slug: 'general' },
});
strapi.log.info('Created default category');
}
},
};
TypeScript
export default {
async bootstrap({ strapi }) {
const categories = await strapi
.documents('api::category.category')
.findMany({ filters: { slug: 'general' }, pageSize: 1 });
if (categories.length === 0) {
await strapi.documents('api::category.category').create({
data: { name: 'General', slug: 'general' },
});
strapi.log.info('Created default category');
}
},
};
Destroy
destroy 函数位于 ./src/index.js(或 ./src/index.ts)中,是一个在应用程序关闭之前运行的异步函数。
destroy 函数可用于优雅地:
更具体地说,destroy() 的一个典型用例是处理运维清理,例如关闭数据库或队列连接,以及移除监听器,以便应用程序能够干净地关闭。
JavaScript
let heartbeat;
module.exports = {
async bootstrap({ strapi }) {
heartbeat = setInterval(() => {
strapi.log.debug('Heartbeat interval running');
}, 60_000);
},
async destroy() {
clearInterval(heartbeat);
},
};
TypeScript
let heartbeat: ReturnType<typeof setInterval>;
export default {
async bootstrap({ strapi }) {
heartbeat = setInterval(() => {
strapi.log.debug('Heartbeat interval running');
}, 60_000);
},
async destroy() {
clearInterval(heartbeat);
},
};
用法
组合使用
全部 3 个生命周期函数可以放在一起,用于在应用程序启动和关闭期间配置自定义行为。
- 决定你的逻辑应该何时运行。
- 将仅初始化的任务(例如注册自定义字段或提供方)放在
register()中。 - 将需要完整 Strapi 访问权限的启动任务(例如植入数据或附加 Webhook)放在
bootstrap()中。 - 将清理逻辑(例如关闭外部连接)放在
destroy()中。
- 将仅初始化的任务(例如注册自定义字段或提供方)放在
- 将代码放在
src/index.js|ts中。保持register()精简,因为它在 Strapi 完全设置之前运行。 - 重新启动 Strapi 以确认每个生命周期按顺序执行。
let cronJobKey: string | undefined;
export default {
register({ strapi }) {
strapi.customFields.register({
name: 'color',
type: 'string',
plugin: 'color-picker',
});
},
async bootstrap({ strapi }) {
cronJobKey = 'log-reminders';
strapi.cron.add({
[cronJobKey]: {
task: async ({ strapi }) => {
strapi.log.info('Remember to review new content in the admin panel.');
},
options: {
rule: '0 */6 * * *', // every 6 hours
},
},
});
},
async destroy({ strapi }) {
if (cronJobKey) {
strapi.cron.remove(cronJobKey);
}
},
};
你可以在 这篇博客文章 中找到关于注册生命周期函数的附加信息。