最近,Ember.PromiseProxyMixin 已添加到 Discourse 核心中的 Ember 模块。
这是一个非常有用的 Ember 混入(mixin),它允许你发起异步请求,并在 Ember 组件中轻松处理 Promise。你可以将其理解为 Ember 版的 React Suspense。对于 Discourse 的主题和插件开发而言,其潜力巨大。
以下是 Ember 官方关于 Ember.PromiseProxyMixin 的文档。
同时,你可以在这里找到一个详细的非 Discourse 示例,展示如何使用 Ember.PromiseProxyMixin。
我将给出一个简单示例,说明如何在 Discourse 主题中使用该混入。假设由于某种原因,在 topic-list-item 组件中,你希望为工作人员成员的头像添加不同的边框样式。
在 topic-list-item.js(.es6) 中的某处,你需要执行以下操作:
- 导入
EmberObject和PromiseProxyMixin,并将EmberObject扩展为包含PromiseProxyMixin。
import EmberObject from "@ember/object";
import PromiseProxyMixin from "@ember/object/promise-proxy-mixin";
const PromiseObject = EmberObject.extend(PromiseProxyMixin);
// 你可以使用自定义的 memoize 函数来防止对同一用户重复请求
const getUser = memoize(username => ajax(`/u/${username}`).then(data => data));
- 然后,你需要创建这些计算属性:
// 计算 Promise
@discourseComputed("topic")
posterPromise(topic) {
const { user } = topic.posters[0];
return getUser(user.username);
},
// 此计算属性(CP)使用 `PromiseObject` 包装 Promise
@discourseComputed("posterPromise")
posterProxy() {
const promise = this.get("posterPromise");
return promise && PromiseObject.create({ promise });
},
posterData: reads("posterProxy.content.user"),
@discourseComputed("posterData")
isStaff() {
const posterData = this.get("posterData");
if (!posterData) return false;
const { groups = [] } = posterData;
// 要检查用户是否为工作人员,我们需要确认
// 该用户是否属于工作人员组
return groups.some(({ name }) => name === "staff");
}
在模板 topic-list-item.hb(r|s) 中,你将拥有类似以下内容:
{{#if posterProxy.isFulfilled}}
{{#if isStaff}}
// 执行你的自定义操作
{{/if}}
{{/if}}
你可以利用 isPending 来显示加载器。
希望这个不太实用的示例能帮助你理解该混入的工作原理,并可能启发你在主题或插件开发中找到使用它的方法。
![]()