首页 > 解决方案 > 带有异步数据的 lodash.template

问题描述

我真的很喜欢_.template函数,我用它来允许用户在他的文本中输入变量,我以后用它来替换一些数据。

唯一的问题是我需要在调用编译的模板函数之前收集所有可选变量数据,这个过程可能需要一些时间,在某些情况下可能是多余的,因为用户不会总是使用所有可选变量。

例如,假设用户发送如下字符串:

ZimGil is <%= age %> and his favorite language is <%= language %>

我需要有ageandlanguage变量,但我不需要有phone需要一些冗余时间才能获得的变量。

试图找出一种方法来根据使用的变量评估模板中的异步函数

标签: javascriptlodash

解决方案


您可以使用正则表达式来获取所有变量名称。

您需要遵循 lodash 允许变量获取所有变量的方法。请参阅模式每个部分旁边的注释以获取解释。

TL;DR:正则表达式是/\<\%[=|-]?(?:[\s]|if|\()*(.+?)(?:[\s]|\)|\{)*\%\>/g(没有字符串转义)。

function getTemplateVariables(template) {
  // making sure the template is a string
  template = template || '';

  const pattern = [
    '<%[=|-]?', // look for opening tag (<%, <%=, or <%-)
    '(?:[\\s]|if|\\()*', // accept any space after opening tag and before identifier
    '(.+?)', // capture the variable name (`luigi` in <%= luigi %>)
    '(?:[\\s]|\\)|\\{)*', // accept any space after identifier and before closing tag
    '%>' // look for closing tag
  ].join('');

  const regex = new RegExp(pattern, 'g');

  const matches = [];

  let match;
  while (match = regex.exec(template)) {
    matches.push(match[1])
  }

  return _.uniq(matches);
}

_.uniq用于删除重复的变量。

更改 lodash 中的模板函数

您可以使用mixin覆盖 lodash 中的模板函数并返回变量:

const originLodashTemplate = _.template;

_.mixin({
  getTemplateVariables, // <-- you can use this on it's own
  template: (...args) => { // <-- or together
    const variables = _.getTemplateVariables(args[0]);
    const template = originLodashTemplate (...args);
    return {
      variables,
      template
    };
  }
});

然后,您可以像这样使用它:

const templateObj = _.template(
  "ZimGil is <%= age %> and his favorite language is <%= language %>"
);

console.log(templateObj.variables);
// will print ["age","language"]
console.log(templateObj.template({ age: "over 5000 years old", language: "turtlese" }));
// will print 'ZimGil is over 5000 years old and his favorite language is turtlese'

异步示例

(async () => {
  const templateObj = _.template(
    "ZimGil is <%= age %> and his favorite language is <%= language %>"
  );
  
  const templateData = {};
  for (const variable of templateObj.variables) {
    const asyncResult = await mapToAsyncCall(variable);
    templateData[variable] = asyncResult;
  }

  // this data will only contain existing variables
  templateObj.template(templateData);
  })();

工作示例

这是一个代码笔,其中包含所有这些工作的示例。

注意

  • 尽管我很确定覆盖_.template是安全的(不要认为它与 lodash 内部的全局指针一起使用),但它可能不是,你可能想给 mixin 函数一个不同的名字!
  • 这不会涵盖高级代码注入,例如_.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');. 您需要将您计划允许的单词添加到正则表达式中,以支持更多识别变量的代码注入。目前,它仅涵盖if语句,但可以在上面的“打开标签之后和之前”正则表达式中添加更多内容。一种完全做到这一点的方法(但这更复杂)是更改原始源代码_.template以实际返回变量并用新代码覆盖它。这将支持 lodash 开箱即用的所有代码注入。

推荐阅读