LeCodesdocs

Сеть

HTTP и сокеты через мост хоста. Читаются как веб-API, но это не они — одно, что нужно усвоить: после того как await fetch(...) разрешился, тело уже на хосте, поэтому res.json() / res.text() синхронны — второго await нет.

Обзор

TypeScript
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

TypeScript
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

TypeScript
res.status          // HTTP-код статуса (только чтение)
res.json<T>(): T    // распарсить тело как JSON — СИНХРОННО
res.text(): string  // тело как текст — СИНХРОННО
res.dispose()       // освободить буфер тела на стороне хоста

Тело живёт в хранилище на стороне хоста; json()/text() перетягивают его. FetchResponse также принимается напрямую как источник изображения (UIImage(res)) и как значение FormData.

Note

json()/text() — обычные синхронные вызовы. await res.json() «работает» (await обычного значения), но выдаёт неверную ментальную модель — не пиши так.

Note

владение — хост держит тело, пока ты не вызовешь dispose() (или ты сделал fetch с useOnce: true). Освобождай ответы, которые держишь, когда закончил с ними.

fetchLocal

TypeScript
fetchLocal(path: string): FetchResponse    // синхронно, статус всегда 200

Читай собранный ресурс проекта — без промиса, без сети. Используй с макросом asset() для файлов данных, которые поставляешь:

TypeScript
const config = fetchLocal(asset('./config.json')).json<{ levels: number }>()

File

TypeScript
file.id      // хэндл буфера на стороне хоста (только чтение)
file.name    // имя файла (только чтение)
file.size    // байты (только чтение)

Хэндл выбранного или снятого файла. Ты их не конструируешь — они приходят из openFilePicker и CameraViewer.takePhoto(). Добавь в FormData для загрузки, используй как источник изображения или share() его.

FormData

TypeScript
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 или итерации.

TypeScript
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

TypeScript
const ws = new WebSocket(url: string, headers?: Record<string, string>)  // подключается сразу
ws.send(message: string | ArrayBuffer)
ws.close()

Событийная поверхность как в браузере, с одним нестандартным дополнением: необязательный аргумент headers идёт на upgrade-запрос (удобно для токенов авторизации). Слушай через addEventListener / removeEventListener (общий паттерн эмиттера — см. Соглашения):

TypeScript
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 экрана, иначе они продолжат работать при навигации.

Подводные камни

TypeScript
// ✗ привычки веб-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)

Смотрите также