Handlebars.js: 功能建议 | 同步/异步助手

创建于 2014-01-23  ·  24评论  ·  资料来源: handlebars-lang/handlebars.js

注册一个助手为同步或异步,它有助于监听回调,并从回调中获取数据。

最有用的评论

打算试试 express-hbs - 但我认为在 2018 年不支持是一件奇怪的事情。 我知道有一个纯粹的观点认为异步的东西不应该作为视图的一部分,而是在一些叫做控制器的神奇东西中完成(好像 MVC 在某种程度上是无可争辩的“正确”)——但这对于两个关键点来说有点短视原因

a) 外部库 - 大多数人现在完全使用 async/await 编写 - 我认为在我的代码中,10 个函数中有 9 个以上是异步的……在某些情况下“以防万一”。 不支持异步函数意味着所有异步库突然完全无法访问

b) 通用控制器功能。 我会争辩这样的事情:

    {{#query "select name, total from summary"}}
          <tr><td>{{this.name}}</td><td>{{this.total}}</td></tr>
    {{/query}}

与将这些内容粘贴到变量中并将其传递到模板中的定制控制器功能相比,它更短、更清洁、更易于维护,并且在所有可以想象的方式上基本上都优于模板,然后模板必须知道和访问。

所有24条评论

这在过去已经出现,但由于用例不清楚,我们没有采取行动。 由于把手仍然必须等到所有数据都可用才能呈现,所以提供异步评估只是一种方便,因为生成上下文的代码可以以更有效的方式执行某些操作。

基本上此时添加异步评估在兼容性和运行时性能方面都非常昂贵,我现在还没有看到一个用例。 你有一个具体的例子来说明你正在尝试做什么吗?

我同意性能问题,但我认为,如果我们可以选择将其设置为 aysnc,例如 RegisterHelper 和 RegisterHelperAsync 或类似的东西,它会更好。

实际上,当我使用 node.js 时,我开始考虑这些异步把手。 我正在使用 express.js 开发一些应用程序,我使用的模板引擎是把手。 因此,如果我需要在编译视图时从数据库调用中获取一些值,那么这种同步工作是不可能的,

例如,

Handlebars.registerHelper('getDbValue', function(id) {
     var Model = require('./myModel.js');
     Model.getValue(id, function(data){
           return data;
     });
});

上面的示例将不起作用,并且不返回任何内容。 以下是我的概念。 而且,我不知道它是否完全正确,或者它是否可以实施。 在异步方法的情况下,只需使用回调函数而不是返回。

Handlebars.registerHelperAsync('getDbValue', function(id, callback) {
     var Model = require('./myModel.js');
     Model.getValue(id, function(data){
           callback(data);
           //or
           //callback(new Handlebars.SafeString(data)); //in case of safestring.
     });
});

我遇到了更多类似上述问题的问题,如果有人对此功能感兴趣,我可以根据我的场景展示更多示例。

谢谢

@robincsamuel ,当在视图生成中包含数据库查找时,MVC 分离的整个想法都在窗口中。 我认为您在争辩说,在呈现视图之前您可能不知道您需要数据,但对我来说,这表明应该在控制器级别而不是在生成视图时实现功能。 结合@kpdecker提到的性能考虑,异步助手似乎是错误的。 -- 我的 2c

我只是用那个例子来表达我的问题。 我并不是要争论,而是提出一个建议。 我希望,如果我们从帮助程序调用一个带有回调的函数会有所帮助。 无论如何,谢谢你的时间:) @kpdecker @jwilm

此时项目的立场是数据解析应该在调用模板之前完成。 在模板关注点内外的业务逻辑之外,异步解析更多是实用行为,其他库(例如异步)更适合处理。

我想评论一些东西。 即使它会将 DB 示例扔出窗外,但这对于突变模板可能非常有帮助。 例如,内部带有“子视图”的模板,并且您不想拆分为其他几个模板。 我只想更新视图中的一部分,并为此有一个简单的逻辑,而不是重新绘制我的整个视图(闪烁效果)或让我的控制器为所有这些“迷你视图”构建整个东西

你怎么认为?

@tomasdev我的意思是:)

如果您使用https://github.com/barc/express-hbs,此功能可在 node 中使用 express。 然而,辅助函数的异步版本不能很好地处理子表达式和其他一些边缘情况。

我希望看到重新考虑将此功能包含在车把中,或者至少考虑车把核心如何更好地支持这种扩展。

我相信 Ghost 为异步助手展示了一个清晰有效(尽管可能不常见)的用例,因为我们的视图层是可定制的。

在前端,Ghost 的所有模板都是由主题提供的。 主题是一个非常薄的把手、CSS 和客户端 JS 层,它可以访问的唯一数据是我们提前提供的数据。 它无权访问控制器或任何行为改变逻辑。 这是非常刻意的。

为了扩展主题 API,我们希望开始添加帮助程序,这些帮助程序定义了主题想要使用的其他数据集合。 例如:

{{#fetch tags}}
.. do something with the list of tags..
{{else}}
No tags available
{{/fetch}}

Ghost 有一个 JSON API,可在内部和外部使用。 所以这个获取查询将映射到我们的浏览标签函数。 它不需要对所有端点使用 ajax/http,相反,异步助手可以在内部从 API 获取这些数据并照常进行。

我不认为这是一个常见的用例,我接受它打破了标准的 MVC 模型,但我相信它是有效且有用的。

@ErisDS好消息! 我也不认为这是常见的问题,但它有帮助。

在这种情况下值得注意的是,我们目前使用异步帮助器的许多操作在后台是同步的,但它们的结构是 Promise。

举个详细的例子...

Ghost 中的所有数据都通过内部 API 访问。 这包括诸如设置之类的全局信息。 对设置 API 的请求在访问数据库之前先访问了预先填充的内存缓存,因此我们实际上只是返回了一个变量,但是通过将其构造为一个承诺,如果需要,可以很容易地访问数据库。

它还确保一切都是一致的——否则设置 API 将是同步的,而所有其他内部数据请求将是异步的,这没有任何意义。

我知道用 Promise 构建所有东西一开始可能会让人很困惑,但是一旦你有了它,你就会不明白没有它是如何生活的。 随着 ES6 中的生成器,对函数异步解析的支持将直接融入 JavaScript - 这个类似的问题: https ://github.com/wycats/handlebars.js/issues/141 提到制作把手会很好与产量一起工作。

我不确定即将发布的 HTMLbars 对此有何影响,但我认为它至少值得进一步讨论。

在尝试为 acl 解析创建帮助程序时遇到了另一个用例。 这很适合我的模板:

        {{#allowedTo 'edit' '/config'}}
            <li>
                <a href="/config">Config</a>
            </li>
        {{/allowedTo}}

但是来自 node-acl 的实际isAllowed方法是异步的(例如,允许数据库后端)。

一种解决方法是事先获取所有用户权限( allowedPermissions ),但这有点痒

@kpdecker对这些用例有什么进一步的想法吗?

@ErisDS我理解这里的愿望,但我严重怀疑这是否会以回调或承诺形式进入语言。 从 API 的角度来看,这是很难干净地完成的事情,并且实际上需要我们重写大部分模板引擎来支持它。 我的建议是在上游模型/数据源进入渲染周期之前处理所有这些。

产量想法是一个有趣的想法,但如果有人想看看那里需要什么,那将是一个了不起的研究项目,但浏览器对此的支持对我来说似乎很遥远,老​​实说,我并没有搞砸我的任何项目中的任何这些功能。

只是我的“两”(嗯,一对)美分你可能想考虑:

  • MVC 不是神圣不可侵犯的。 事情并没有错,因为它们似乎与 MVC 相矛盾。 必须评估替代方案是否不会比严格遵循 MVC 提供净正面收益。
  • 如果视图直接向控制器询问数据,而不是直接向模型询问,这无论如何都不会违反 MVC,是吗?
  • 可能有人会说,让控制器事先知道视图需要的所有信息是信息的重复(即“X、Y、Z、W 是必要的”信息在视图和控制器中是重复的。)换句话说,我们当前的实践可能违反了 DRY 原则,这比 MVC 重要得多,imo。
  • 异步帮助器的性能损失可以通过从数据库加载更少的数据来轻松补偿,因为它只加载正在呈现的视图所需的模型。

我也许可以提供一个更好的例子,它会很有用。

我们为移动应用程序使用了cordova,并且需要针对多种语言进行本地化。 Cordova 提供了帮助格式化日期、数字、货币等的功能。
问题是它们都需要异步回调。

例子:

Handlebars.registerHelper('stringToNumber', function(string, type)
{
    type = type || 'decimal';
    navigator.globalization.stringToNumber(string, function(number)
    {
        return number;
    }, function()
    {
        return NaN;
    }, {
        type: type
    });
});

拥有imo真是太棒了。

我在 npm 上找到了 handlebars-async包。 但它有点旧,我不知道它是否适用于当前的 Handlebars 版本。

我也刚刚为 promises 写了一些类似的东西。 包 promise -handlebars允许您从助手内部返回承诺。 我计划在我的一个项目中使用它,但到目前为止它还没有在生产环境中使用。 但是有几个边缘情况的单元测试(例如从异步块助手中调用异步助手),它们都是绿色的......

@nknapp听起来很棒! express-hbs具有异步支持,并且异步适用于块助手,但嵌套异步助手不起作用 - 所以我真的很想看到这个工作 - 意味着 express-hbs 仍有希望:+1:

@ErisDS ,你认为我应该把它贴在那里。 我现在不知道express-hbs不能嵌套异步助手。 我的主要关注点不是express ,而是我目前正在研究的 README 生成器。 我真的很感谢其他人尝试它(承诺的车把)提供反馈。

要添加到有效的用例中,如果您需要根据当前语言环境从翻译数据库中获取值怎么办?

<div class="howItWorks">
    {{{i18nFetch id=how-it-works locale=locale}}}
</div>

此外,如何使用动态 id 从 DB 条目添加 CMS 块,例如:

<div class="searchCms">
    {{{cmsLoader 'search-{$term}' term=params.input defaultId='search-default'}}}
</div>

这对于服务器端渲染(即使用express-handlebars )特别有用。

这是另一个用例:我正在为 Swagger ( simple-swagger ) 编写一个文档生成器,它允许外部模式定义。 我想编写一个 Handlebars 帮助器,它可以识别何时在外部定义模式,转到该模式所在的提供的 URL,检索它,并使用该数据呈现 Handlebars 模板的该部分。 如果我必须在调用 Handlebars 的 compile 方法之前检索这些数据,我将不得不递归地遍历一个我事先不知道其结构的 JSON 文档,找到所有外部模式的实例,检索它们,然后将它们插入到JSON。

基本上,只要使用 Handlebars 模板呈现 JSON 模式数据 ( json-schema.org ),异步呈现方法就会很有用,因为 JSON 模式总是允许在外部定义模式的子部分。

@dwhieb你看过 bootprint -swagger的文档生成器吗? 这几乎就是您所描述的(除了尚未实现外部模式,但这将是一个很棒的功能)。 如果您有任何反馈,请在此处打开问题。

而且,我认为promise-handlebars与异步助手配合得很好。

我有一个用例,能够在助手中使用 Promise 会很有用。 我正在使用把手为我的博客生成 HTML。 为了为每篇文章构建有效的结构化数据,我需要获取用于文章图像的维度。 现在,我正在这样做:

{{#imageSize post.frontMatter.previewImage}}
  <div itemprop="image" itemscope itemtype="https://schema.org/ImageObject">
    <meta itemprop="url" content="{{#staticResource ../post.frontMatter.previewImage}}{{/staticResource}}">
    <meta itemprop="width" content="{{width}}">
    <meta itemprop="height" content="{{height}}">
  </div>
{{/imageSize}}

imageSize帮助器工作是因为它同步读取文件,但理想情况下它应该能够异步执行,因此渲染页面不会因 I/O 而减慢。 此外,对 URL 上的图像而不是文件系统上的图像执行此操作是不可能的。

我会考虑使用promised-handlebars 和express-hbs,但我认为在辅助函数中使用promises 的能力将是对Handlebars 的一个很好的补充!

FWIW,我一直在使用 Hyperscript、 hyperscript-helpers 、ES7 的async/await进行很多异步 HTML 渲染,这真的很开心。 但当然,该解决方案仅适用于 HTML。 使用 Handlebars 的异步解决方案可以让我们异步生成其他类型的文件……但是对于 HTML,我想我永远不会回头!

打算试试 express-hbs - 但我认为在 2018 年不支持是一件奇怪的事情。 我知道有一个纯粹的观点认为异步的东西不应该作为视图的一部分,而是在一些叫做控制器的神奇东西中完成(好像 MVC 在某种程度上是无可争辩的“正确”)——但这对于两个关键点来说有点短视原因

a) 外部库 - 大多数人现在完全使用 async/await 编写 - 我认为在我的代码中,10 个函数中有 9 个以上是异步的……在某些情况下“以防万一”。 不支持异步函数意味着所有异步库突然完全无法访问

b) 通用控制器功能。 我会争辩这样的事情:

    {{#query "select name, total from summary"}}
          <tr><td>{{this.name}}</td><td>{{this.total}}</td></tr>
    {{/query}}

与将这些内容粘贴到变量中并将其传递到模板中的定制控制器功能相比,它更短、更清洁、更易于维护,并且在所有可以想象的方式上基本上都优于模板,然后模板必须知道和访问。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

ShintaroOkuda picture ShintaroOkuda  ·  7评论

ustun picture ustun  ·  6评论

fcpauldiaz picture fcpauldiaz  ·  4评论

janus-reith picture janus-reith  ·  3评论

amirzandi picture amirzandi  ·  7评论