🦉 Служебные функции (Utils) 🦉

Owl экспортирует несколько полезных служебных функций, чтобы помочь с распространенными проблемами. Все эти функции доступны в пространстве имен owl.utils.

Содержимое

  • whenReady: выполнение кода, когда DOM готов
  • loadJS: загрузка файлов скриптов
  • loadFile: загрузка файла (полезно для шаблонов)
  • escape: очистка строк
  • debounce: ограничение частоты вызовов функций
  • shallowEqual: сравнение неглубоких объектов

whenReady

Функция whenReady возвращает Promise, разрешенное, когда DOM будет готов (если оно еще не готово, в противном случае разрешается напрямую). Если вызывается с обратным вызовом в качестве аргумента, он выполняет его, как только DOM готов (или напрямую).

Promise.all([loadFile("templates.xml"), owl.utils.whenReady()]).then(function ([templates]) {
  const qweb = new owl.QWeb({ templates });
  const env = { qweb };
  await mount(App, { env, target: document.body });
});

или еще вариант:

owl.utils.whenReady(function () {
  const qweb = new owl.QWeb();
  const env = { qweb };
  await mount(App, { env, target: document.body });
});

loadJS

loadJS принимает URL-адрес (строку) ресурса javascript и загружает его (путем добавления тега script в заголовок документа). Он возвращает промис, поэтому вызывающая сторона может правильно отреагировать, когда он будет готово. Кроме того, он умен: он поддерживает список URL-адресов, загруженных ранее (или загружаемых в настоящее время), и предотвращает двойную работу.

Например, это полезно для ленивой загрузки внешних библиотек:

class MyComponent extends owl.Component {
  willStart() {
    return owl.utils.loadJS("/static/libs/someLib.js");
  }
}

loadFile

loadFile — это вспомогательная функция для загрузки файла. Он просто выполняет запрос GET и возвращает результирующую строку в промисе. Первоначальный вариант использования этой функции — загрузить файл шаблона. Например:

async function makeEnv() {
  const templates = await owl.utils.loadFile("templates.xml");
  const qweb = new owl.QWeb({ templates });
  return { qweb };
}

Обратите внимание, что в отличие от loadJS, эта функция возвращает содержимое файла в виде строки. Он не добавляет тег script и не делает ничего.

escape

Иногда нам нужно отобразить динамические данные (например, данные, созданные пользователем) в пользовательском интерфейсе. Если это делается с помощью шаблона QWeb, это не проблема:

    <div><t t-esc="user.data"/></div>

Механизм QWeb создаст узел div и добавит содержимое строки user.data в качестве текстового узла, поэтому веб-браузер не будет анализировать его как html. Однако это может быть проблемой, если это делается с помощью кода javascript, подобного этому:

class BadComponent extends Component {
  // какой то шаблон с ref в div
  // какой-то код ...

  mounted() {
    this.divRef.el.innerHTML = this.state.value;
  }
}

В этом случае содержимое div будет проанализировано как html, что может привести к нежелательному поведению. Чтобы исправить это, функция escape просто преобразует строку в экранированную версию той же строки, которая будет правильно отображаться браузером, но не будет анализироваться как html (например, "<ok>" экранируется в строку: "&lt;ok&gt;"). Итак, плохой пример выше можно исправить следующим изменением:

this.divRef.el.innerHTML = owl.utils.escape(this.state.value);

debounce

Функция debounce полезна, когда мы хотим ограничить количество раз выполнения какой-либо функции/действия. Например, это может быть полезно для предотвращения проблем с двойным нажатием кнопки.

Она принимает три аргумента:

  • func (функция): это функция, скорость которой будет ограничена.
  • wait (число): это количество миллисекунд, которое мы хотим использовать для ограничения скорости функции func
  • immediate (необязательный, логическое значение, по умолчанию=false): если immediate равно true, функция будет запущена немедленно (по переднему фронту интервала). Если false, функция будет запущена в конце (по заднему фронту).

Она возвращает функцию. Например:

const debounce = owl.utils.debounce;
window.addEventListener("mousemove", debounce(doSomething, 100));

Как показывает этот пример, такое бывает полезно для обработчиков событий, которые запускаются очень быстро, например для таких событий scroll или mousemove.

shallowEqual

Эта функция проверяет, имеют ли два объекта одинаковые значения, назначенные каждому ключу:

shallowEqual({ a: 1, b: 2 }, { a: 1, b: 2 }); // true
shallowEqual({ a: 1, b: 2 }, { a: 1, b: 3 }); // false

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

const completeShallowEqual = (a, b) => shallowEqual(a, b) && shallowEqual(b, a);