Обработка промисов

SkateJS — это легковесная библиотека для создания веб-компонентов на базе стандартов Custom Elements, которая тесно интегрируется с современными возможностями JavaScript, включая асинхронные операции через промисы. В SkateJS промисы используются для управления состояниями компонентов, выполнения асинхронной логики при рендеринге и обработки данных, получаемых из внешних источников.

Промис (Promise) в SkateJS, как и в стандартном JavaScript, представляет собой объект, который может находиться в одном из трёх состояний: pending, fulfilled, rejected. В контексте компонентов SkateJS это позволяет организовать асинхронные операции, не блокируя основной поток рендеринга.


Создание и возврат промисов в методах компонентов

Методы компонентов SkateJS часто возвращают промисы для работы с асинхронными данными. Например, можно определить метод loadData, который возвращает промис и обновляет состояние компонента после завершения асинхронной операции:

import { define, Component, html } from 'skatejs';

class AsyncComponent extends Component {
  static get props() {
    return {
      data: { default: null }
    };
  }

  loadData() {
    return fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(json => {
        this.data = json;
      })
      .catch(error => {
        console.error('Ошибка при загрузке данных:', error);
      });
  }

  render() {
    return html`
      <div>
        ${this.data ? JSON.stringify(this.data) : 'Загрузка...'}
      </div>
    `;
  }
}

define('async-component', AsyncComponent);

Ключевой момент: промис позволяет компоненту оставаться реактивным и корректно обновлять DOM после завершения асинхронной операции.


Асинхронный рендеринг с использованием промисов

SkateJS поддерживает интеграцию с промисами на уровне рендеринга. Если метод render возвращает промис, библиотека автоматически обновляет содержимое после его разрешения. Это особенно полезно при работе с данными из API или локальными асинхронными источниками.

render() {
  return fetch('https://api.example.com/user')
    .then(res => res.json())
    .then(user => html`<p>${user.name}</p>`);
}

В этом примере SkateJS подождёт завершения промиса и отобразит результат в DOM без необходимости вручную обновлять компонент.


Использование async/await для упрощения промисов

Современный синтаксис async/await делает код компонентов более читаемым и структурированным. Промисы внутри методов можно обрабатывать синхронным стилем:

async loadUser() {
  try {
    const response = await fetch('https://api.example.com/user');
    const user = await response.json();
    this.data = user;
  } catch (error) {
    console.error('Ошибка загрузки пользователя:', error);
  }
}

Особенность SkateJS: использование async/await совместимо с реактивной системой компонентов. Изменение свойства this.data после завершения промиса инициирует обновление DOM автоматически.


Промисы и жизненный цикл компонентов

Асинхронные операции часто выполняются на этапах жизненного цикла компонентов:

  • connectedCallback — вызов промисов при подключении компонента к DOM.
  • updated — выполнение асинхронной логики после изменения свойств.
  • disconnectedCallback — возможность отмены или очистки незавершённых промисов.

Пример использования промиса в connectedCallback:

connectedCallback() {
  super.connectedCallback();
  this.loadData();
}

Для предотвращения утечек памяти и нежелательных изменений после удаления компонента рекомендуется использовать флаги или AbortController:

async loadData() {
  const controller = new AbortController();
  this._abortController = controller;

  try {
    const response = await fetch('https://api.example.com/data', { signal: controller.signal });
    const data = await response.json();
    this.data = data;
  } catch (error) {
    if (error.name !== 'AbortError') {
      console.error(error);
    }
  }
}

disconnectedCallback() {
  if (this._abortController) {
    this._abortController.abort();
  }
  super.disconnectedCallback();
}

Комбинирование нескольких промисов

Часто необходимо выполнять несколько асинхронных операций одновременно. SkateJS позволяет использовать стандартные методы работы с промисами: Promise.all, Promise.race, Promise.allSettled.

async loadMultiple() {
  try {
    const [users, posts] = await Promise.all([
      fetch('https://api.example.com/users').then(res => res.json()),
      fetch('https://api.example.com/posts').then(res => res.json())
    ]);
    this.users = users;
    this.posts = posts;
  } catch (error) {
    console.error('Ошибка при загрузке данных:', error);
  }
}

Преимущество: параллельная загрузка данных уменьшает задержку и позволяет компоненту отображать результат быстрее, чем последовательные промисы.


Обработка ошибок промисов

SkateJS не перехватывает исключения промисов автоматически. Для безопасной работы рекомендуется оборачивать асинхронные методы в try/catch или использовать .catch(). Это предотвращает неожиданные сбои и позволяет компоненту сохранять корректное состояние.

async fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) throw new Error('Сетевая ошибка');
    this.data = await response.json();
  } catch (error) {
    this.error = error.message;
  }
}

В реактивном рендере можно отображать состояние ошибки:

render() {
  if (this.error) return html`<p>Ошибка: ${this.error}</p>`;
  return html`<p>${this.data ? JSON.stringify(this.data) : 'Загрузка...'}</p>`;
}

Промисы и свойства компонентов

Асинхронные операции часто связаны с изменением свойств компонента. SkateJS обеспечивает автоматическую реактивность: обновление свойства, ассоциированного с промисом, инициирует повторный рендер.

static get props() {
  return {
    data: { default: null },
    loading: { default: false }
  };
}

async loadData() {
  this.loading = true;
  try {
    const response = await fetch('https://api.example.com/data');
    this.data = await response.json();
  } finally {
    this.loading = false;
  }
}

render() {
  return html`
    ${this.loading ? html`<p>Загрузка...</p>` : html`<pre>${JSON.stringify(this.data)}</pre>`}
  `;
}

Такой подход упрощает управление состояниями компонентов при асинхронных операциях и делает код предсказуемым.


Особенности интеграции с сторонними библиотеками

Промисы в SkateJS легко комбинируются с внешними библиотеками для работы с данными, включая GraphQL, Axios или IndexedDB. Главное — сохранять реактивность через свойства компонента и использовать async/await или .then() для обработки результатов. Это позволяет компонентам оставаться лёгкими, модульными и полностью управляемыми в асинхронной среде.