是否可以从 Ember 模板中的 HTMLBars 异常中恢复?

Is it possible to recover from HTMLBars exception in Ember template?

我有一个动态组件类似于:

{{component fooProperty owner=this}}

fooProperty 是数据驱动的,有时会错误地关闭,至少现在在开发中是这样,但恐怕它也可能在产品中错误地关闭(由于应用程序版本控制、持久存储等)。基本上,我不相信这总是正确的(即可解析为组件)。当该值关闭时,整个应用程序会崩溃:

Uncaught Error: Assertion Failed: HTMLBars error: Could not find component named "some-inexisting-component" (no component or template with that name was found)
 EmberError @ ember.debug.js:19700
 assert @ ember.debug.js:6719
 assert @ ember.debug.js:19502
 componentHook @ ember.debug.js:10894
 render @ ember.debug.js:12782
 render @ ember.debug.js:12732
 handleKeyword @ ember.debug.js:46584
 keyword @ ember.debug.js:46709
 exports.default @ ember.debug.js:12483
 handleKeyword @ ember.debug.js:46545
 handleRedirect @ ember.debug.js:46531
...

我更愿意捕获此类异常并防止整个应用程序崩溃。我可以想到一个解决方法,例如。审查 fooProperty return 与 App.__container__.lookup 和 return 通用 'missing' 组件。但如果可能的话,我仍然希望有一种方法可以捕获和处理渲染过程中引发的异常。

生产构建中不会出现断言错误。所以你的应用程序不会崩溃。如果组件存在,它将呈现,否则它将默默地失败。

简单的答案是"No, but you can implement your own."模板引擎从来没有异常处理的作用。它不仅与 Handlebars/HTMLbars 案例相关,而且与 JSX、Jinja 等其他模板引擎相关,因为异常处理涉及相当多的逻辑,必须在用户端指定,而且它似乎不在演示范围内他们所扮演的角色。主要原因似乎是 Ember 框架开发人员希望强制执行的关注点分离,以避免开发人员最终在他们的应用程序中使用大量额外的意大利面条代码,这会大大降低整体代码的可读性和可维护性。

针对您的情况的可能解决方案:

component.js

import Component from 'ember-component';
import get from 'ember-metal/get';
import getOwner from 'ember-owner/get';
import { isEmpty } from 'ember-utils';
import computed from 'ember-computed';

export default Component.extend({
    wantToRenderComponentName: 'name-that-doesnt-exist',
    wantToRenderComponentNameExist: computed('wantToRenderComponentName', {
        get() {
            const owner = getOwner(this);
            return !isEmpty(owner.lookup(`component:${get(this, 'wantToRenderComponentName')}`))
        }
    })    
});

template.hbs

{{#if wantToRenderComponentNameExist}}
    {{component wantToRenderComponentName}}
{{else}}
    // handle your exception presentationally here
{{/if}}

如果 owner.lookup('component:component-name') 是在应用程序中初始化的组件实例,则 owner.lookup('component:component-name') 将是组件实例;否则,undefined 将是组件实例。我可以想象在某些情况下,如果满足某些条件以节省内存,您希望在 运行 时间初始化某些组件,所以这是检查组件是否在应用程序中初始化并且可以在中使用的方法一个模板。这不是异常处理,因为此代码中没有引发异常,但它使用动态组件命名,这就是为什么我们可以将组件是否存在的实际检查移动到 运行-time 以区别于编译时您静态指定要呈现的组件的名称。