Сеть
HTTP и сокеты через мост хоста. Читаются как веб-API, но это не они — одно, что нужно усвоить:
после того как await fetch(...) разрешился, тело уже на хосте, поэтому res.json() /
res.text() синхронны — второго await нет.
Обзор
const res = await fetch('https://api.example.com/items')
if (res.status === 200) {
const items = res.json<{ id: number, name: string }[]>() // синхронно — без await
console.log(items.length)
}
res.dispose()fetch
fetch(url: string, options?: {
method?: string // 'GET' (по умолчанию), 'POST', …
headers?: Record<string, string>
body?: any // строка или FormData
useOnce?: boolean // одноразовое тело — хост может освободить его после чтения
onProgress?: (p: { loaded: number, total?: number }) => void // прогресс загрузки, байты
}): Promise<FetchResponse>Промис разрешается, как только у хоста есть весь ответ — статус и тело. HTTP-статус ошибки (404,
500) всё равно разрешается; проверяй res.status. Отклонение означает, что сам запрос
провалился (нет соединения, плохой URL).
onProgress сообщает скачанные байты; total отсутствует, когда сервер не присылает длину.
Передавай useOnce: true для запросов «выстрелил и забыл», чьё тело ты читаешь ровно один раз — так
делают собственные загрузчики SDK (Texture2D.load, Model.load).
FetchResponse
res.status // HTTP-код статуса (только чтение)
res.json<T>(): T // распарсить тело как JSON — СИНХРОННО
res.text(): string // тело как текст — СИНХРОННО
res.dispose() // освободить буфер тела на стороне хостаТело живёт в хранилище на стороне хоста; json()/text() перетягивают его. FetchResponse также
принимается напрямую как источник изображения (UIImage(res)) и как значение FormData.
json()/text() — обычные синхронные вызовы. await res.json() «работает» (await обычного
значения), но выдаёт неверную ментальную модель — не пиши так.
владение — хост держит тело, пока ты не вызовешь dispose() (или ты сделал fetch с useOnce: true). Освобождай ответы, которые держишь, когда закончил с ними.
fetchLocal
fetchLocal(path: string): FetchResponse // синхронно, статус всегда 200Читай собранный ресурс проекта — без промиса, без сети. Используй с макросом asset() для файлов
данных, которые поставляешь:
const config = fetchLocal(asset('./config.json')).json<{ levels: number }>()File
file.id // хэндл буфера на стороне хоста (только чтение)
file.name // имя файла (только чтение)
file.size // байты (только чтение)Хэндл выбранного или снятого файла. Ты их не конструируешь — они приходят из
openFilePicker и CameraViewer.takePhoto().
Добавь в FormData для загрузки, используй как источник изображения или
share() его.
FormData
const form = new FormData()
form.append(name: string, value: string | number | boolean | File | FetchResponse,
filename?: string) // filename по умолчанию — собственное имя File
form.delete(name: string) // удаляет первое поле с этим именемСобери multipart-тело, затем передай его как body у fetch. Это минимальное подмножество — нет
get, has, set или итерации.
const file = await openFilePicker({ accept: 'image/*' })
if (file) {
const form = new FormData()
form.append('avatar', file)
form.append('userId', 123)
await fetch('https://api.example.com/upload', { method: 'POST', body: form })
}WebSocket
const ws = new WebSocket(url: string, headers?: Record<string, string>) // подключается сразу
ws.send(message: string | ArrayBuffer)
ws.close()Событийная поверхность как в браузере, с одним нестандартным дополнением: необязательный аргумент
headers идёт на upgrade-запрос (удобно для токенов авторизации). Слушай через addEventListener /
removeEventListener (общий паттерн эмиттера — см. Соглашения):
ws.addEventListener('open', () => ws.send('hello'))
ws.addEventListener('message', data => console.log('got', data)) // текстовый или бинарный фрейм
ws.addEventListener('close', code => console.log('closed', code))
ws.addEventListener('error', () => console.log('socket error'))После close() сокет инертен — дальнейшие вызовы send() — тихие no-op. Закрывай сокеты в
onClose экрана, иначе они продолжат работать при навигации.
Подводные камни
// ✗ привычки веб-fetch — читатели тела здесь не асинхронны
const data = await (await fetch(url)).json()
// ✓ дождись fetch один раз, затем читай синхронно
const res = await fetch(url); const data = res.json()
// ✗ считать 404 отклонением
try { await fetch(url) } catch { /* ждём тут 404 — он не придёт */ }
// ✓ HTTP-статусы разрешаются; проверяй статус сам
const res = await fetch(url); if (res.status !== 200) handleError(res.status)Смотрите также
- Файлы и шеринг — откуда берутся хэндлы
File. - Хранилище — хранить небольшое состояние локально вместо сервера.
- Соглашения — события, макрос
asset().