Mithril.js предоставляет лёгкий и эффективный механизм работы с
асинхронными операциями и состояниями загрузки, что особенно важно при
построении одностраничных приложений с динамическим контентом. Основные
инструменты для этих задач — m.request и управление
состоянием компонентов через свойства объекта state или
локальные переменные.
m.requestm.request является встроенным способом выполнения
HTTP-запросов. Основные параметры:
m.request({
method: "GET",
url: "/api/data",
params: { limit: 10 },
})
.then(function(result) {
console.log(result);
})
.catch(function(error) {
console.error(error);
});
Особенности:
Promise, что позволяет использовать
.then() и .catch().params для передачи query-параметров
и body для POST-запросов.Для улучшения читаемости кода часто используют синтаксис
async/await:
async function loadData() {
try {
const data = await m.request({ method: "GET", url: "/api/data" });
console.log(data);
} catch (error) {
console.error(error);
}
}
В Mithril отсутствует встроенный глобальный менеджер состояния, поэтому состояние загрузки управляется локально в компоненте. Чаще всего применяются следующие подходы:
const DataComponent = {
loading: true,
data: null,
oninit: async function() {
try {
this.data = await m.request({ method: "GET", url: "/api/data" });
} catch (e) {
console.error(e);
} finally {
this.loading = false;
}
},
view: function() {
if (this.loading) return m("p", "Загрузка данных...");
return m("ul", this.data.map(item => m("li", item.name)));
}
};
Ключевые моменты:
loading используется для отображения
индикатора.oninit гарантирует, что запрос
начнётся при инициализации компонента.finally обеспечивает корректное завершение
состояния загрузки независимо от результата запроса.state объектаДля более сложных компонентов удобно хранить данные в объекте
state:
const DataComponent = {
state: {
loading: true,
data: [],
error: null
},
oninit: async function(vnode) {
try {
vnode.state.data = await m.request({ method: "GET", url: "/api/data" });
} catch (e) {
vnode.state.error = e;
} finally {
vnode.state.loading = false;
}
},
view: function(vnode) {
const { loading, data, error } = vnode.state;
if (loading) return m("p", "Загрузка данных...");
if (error) return m("p.error", "Ошибка загрузки данных");
return m("ul", data.map(item => m("li", item.name)));
}
};
Преимущества vnode.state:
Асинхронные операции требуют продуманной обработки ошибок и возможности повторной загрузки:
const DataComponent = {
state: { loading: false, data: [], error: null },
oninit: function(vnode) { vnode.state.loadData(); },
loadData: async function() {
this.state.loading = true;
this.state.error = null;
try {
this.state.data = await m.request({ url: "/api/data" });
} catch (e) {
this.state.error = "Не удалось загрузить данные";
} finally {
this.state.loading = false;
}
},
view: function(vnode) {
const { loading, data, error } = vnode.state;
if (loading) return m("p", "Загрузка...");
if (error) return m("div",
m("p.error", error),
m("button", { onclick: () => vnode.state.loadData() }, "Повторить попытку")
);
return m("ul", data.map(item => m("li", item.name)));
}
};
Особенности:
loadData.state.При работе с m.route полезно загружать данные до
отображения страницы. Mithril поддерживает асинхронные маршруты:
m.route(document.body, "/users", {
"/users": {
onmatch: async function() {
const users = await m.request({ url: "/api/users" });
return {
view: () => m("ul", users.map(u => m("li", u.name)))
};
}
}
});
Преимущества:
m.stream для реактивного состоянияMithril предоставляет m.stream, который позволяет
автоматически обновлять представление при изменении данных:
const dataStream = m.stream([]);
const DataComponent = {
oninit: async function() {
const result = await m.request({ url: "/api/data" });
dataStream(result);
},
view: function() {
if (dataStream().length === 0) return m("p", "Загрузка...");
return m("ul", dataStream().map(item => m("li", item.name)));
}
};
Особенности:
m.stream создаёт реактивную переменную, автоматически
обновляющую DOM при изменении.vnode.state.async/await для улучшения читаемости
асинхронного кода.m.stream) или отдельные сервисы для загрузки данных.Эти методы обеспечивают гибкость и позволяют поддерживать чистую архитектуру приложения на Mithril при работе с динамическим контентом и асинхронными запросами.