FAST Element предоставляет мощный механизм для построения веб-компонентов с высокой производительностью, и одним из ключевых инструментов для управления асинхронным поведением являются асинхронные директивы. Они позволяют управлять динамическим контентом, который зависит от промисов, наблюдаемых данных или внешних источников, без необходимости вручную следить за состоянием загрузки и повторного рендеринга.
Асинхронные директивы в FAST Element — это функции, которые могут возвращать значения, промисы или другую директиву, управляя тем, как именно элемент обновляет DOM при изменении состояния. Основная цель — обеспечить эффективное и плавное обновление содержимого, когда данные становятся доступны.
Ключевые свойства асинхронных директив:
html и repeat.asyncДиректива async является стандартным способом работы с
промисами в FAST Element. Она принимает промис и возвращает одно из трёх
состояний:
import { html, FASTElement, async } from "@microsoft/fast-element";
class AsyncExample extends FASTElement {
dataPromise = fetch("/api/data").then(res => res.json());
}
AsyncExample.define();
html`
<div>
${async(this.dataPromise, {
pending: html`<span>Загрузка...</span>`,
fulfilled: html`<span>${x => x}</span>`,
rejected: html`<span>Ошибка загрузки</span>`
})}
</div>
`
Разбор работы:
pending — шаблон, который отображается до завершения
промиса.fulfilled — шаблон для успешного выполнения промиса,
получаемое значение доступно через коллбек.rejected — шаблон, который рендерится в случае
ошибки.Асинхронная директива автоматически отслеживает текущее состояние промиса и предотвращает перерисовку предыдущих результатов при смене промиса.
В реальных приложениях часто требуется работать с несколькими промисами одновременно. Для этого FAST Element поддерживает композицию директив:
html`
${async(this.userPromise, {
pending: html`<span>Загрузка пользователя...</span>`,
fulfilled: html`
<div>
<p>Имя: ${x => x.name}</p>
${async(this.postsPromise, {
pending: html`<span>Загрузка постов...</span>`,
fulfilled: html`
<ul>${x => x.map(post => html`<li>${post.title}</li>`)}</ul>
`,
rejected: html`<span>Ошибка при загрузке постов</span>`
})}
</div>
`,
rejected: html`<span>Ошибка при загрузке пользователя</span>`
})}
`
Особенности:
async позволяют создавать цепочки
асинхронных зависимостей.repeat для динамических списков,
загружаемых из промисов.ref и состояниями компонентаАсинхронные директивы хорошо интегрируются с реактивными свойствами FAST Element:
class MyComponent extends FASTElement {
static properties = {
userId: { type: Number },
userData: { type: Object }
};
connectedCallback() {
super.connectedCallback();
this.loadUser();
}
loadUser() {
this.userData = async(fetch(`/api/users/${this.userId}`).then(r => r.json()));
}
}
html`
<div>
${async(this.userData, {
pending: html`<span>Загрузка пользователя...</span>`,
fulfilled: html`<p>${x => x.name}</p>`,
rejected: html`<span>Ошибка</span>`
})}
</div>
`
Преимущества подхода:
async автоматически реагирует на смену
промиса при изменении свойства.Асинхронные директивы поддерживают мемоизацию промисов, что предотвращает повторные запросы при повторном рендеринге:
html`
${async(() => this.cachedPromise, { /* шаблоны */ })}
`
async повторно использует уже завершённые промисы, если
объект промиса не изменился.Встроенный механизм rejected позволяет централизованно
обрабатывать ошибки промисов, избегая необходимости писать try/catch в
каждом методе:
${async(this.dataPromise, {
pending: html`<span>Загрузка...</span>`,
fulfilled: html`<span>${x => x}</span>`,
rejected: html`<span style="color:red;">Ошибка: ${x => x.message}</span>`
})}
x в блоке rejected содержит объект
ошибки.repeat и динамическими спискамиАсинхронные директивы отлично работают с repeat для
отображения данных после их загрузки:
${async(this.itemsPromise, {
pending: html`<span>Загрузка списка...</span>`,
fulfilled: html`
<ul>
${x => x.map(item => html`<li>${item.name}</li>`)}
</ul>
`,
rejected: html`<span>Ошибка загрузки списка</span>`
})}
repeat используется только внутри
fulfilled для рендеринга окончательного результата.Асинхронные директивы FAST Element обеспечивают чистый и декларативный способ работы с промисами, позволяя создавать динамические и отзывчивые компоненты без лишнего кода для управления состояниями. Их интеграция с шаблонами, реактивными свойствами и другими директивами делает их центральным инструментом при построении сложных интерфейсов с асинхронными данными.