Lodash.template с асинхронными данными

#javascript #lodash

#javascript #Lodash

Вопрос:

Мне очень нравится функция _.template, и я использую ее, чтобы позволить пользователю вводить переменные в свой текст, который я позже использую для замены некоторых данных.

Единственная проблема заключается в том, что мне нужно собрать все данные необязательных переменных перед вызовом скомпилированной функции шаблона, и этот процесс может занять некоторое время, которое в некоторых случаях может быть избыточным, поскольку пользователь не всегда будет использовать все необязательные переменные.

например, допустим, пользователь отправляет строку типа:

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

Мне нужно иметь age language переменные and, но мне не нужна phone переменная, для получения которой требуется некоторое избыточное время.

Пытаюсь найти способ оценки асинхронных функций в шаблоне на основе используемых переменных

Ответ №1:

Вы можете использовать регулярное выражение для получения всех имен переменных.

Вам нужно следовать тому, что 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

Вы можете переопределить функцию шаблона в Lodash с помощью mixin, а также возвращать переменные:

 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] = asyncResu<
  }

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

Рабочий пример

Вот codepen с примером того, как все это работает.

УВЕДОМЛЕНИЕ

  • Хотя я почти уверен, что переопределение _.template безопасно (не думаю, что оно используется с глобальным указателем изнутри Lodash), это может быть не так, и вы можете захотеть присвоить функции mixin другое имя!
  • Это не будет охватывать расширенную инъекцию кода, например _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>'); . вам нужно добавить слова, которые вы планируете разрешить, в регулярное выражение, чтобы поддерживать больше инъекций кода, которые распознают переменные. Прямо сейчас он охватывает только if операторы, но в регулярное выражение «после открытия тега и до» выше можно добавить больше. Способ сделать это полностью (но это намного сложнее) — изменить исходный исходный код _.template , чтобы фактически возвращать переменные и переопределять его новым кодом. Это будет поддерживать все инъекции кода, которые Lodash поддерживает из коробки.

Комментарии:

1. console.log(templateObj.variables); не работает. variables является неизвестным ключом

2. @Pian0_M4n Мне нужно больше информации, чтобы иметь возможность помочь 🙂 где вы пытались добавить журнал консоли? как вы использовали данные функции?