소스 정보
- 저장소
- ryuever/x-oasis
- 최근 소스 활동
- 2026년 4월 30일 06:20
- 감지된 SKILL.md 언어
- 중국어
- 스타
- 0
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/ryuever/x-oasis --skill stream-processing명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
| name | stream-processing |
| description | 使用 web-stream、push-stream 和 event-stream 工具处理流式数据。处理异步迭代、SSE 解析和实时数据流。 |
当你需要以下操作时使用此技能:
import { toAsyncIterable } from '@x-oasis/web-stream';
import { PushStream } from '@x-oasis/push-stream';
import { EventStream } from '@x-oasis/event-stream';
// 将 ReadableStream 转换为异步可迭代
const response = await fetch('/api/data');
for await (const chunk of toAsyncIterable(response.body!)) {
console.log('块:', chunk);
}
// 为手动控制创建推送流
const stream = new PushStream<string>();
stream.enqueue('data1');
stream.enqueue('data2');
stream.done();
for await (const item of stream) {
console.log('项目:', item);
}
// 带聚合的事件流
const eventStream = new EventStream<number>();
eventStream.push(1);
eventStream.push(2);
const result = await eventStream.result();
console.log('最终结果:', result);
| 类/函数 | 目的 | 用例 |
|---|---|---|
toAsyncIterable(readableStream) | 转换为异步迭代器 | 像迭代器一样处理流 |
PushStream<T> | 手动控制流 | 以程序方式生成数据 |
EventStream<T> | 推拉桥 | 聚合最终结果 |
parseJsonEventStream() | 解析 SSE JSON | 处理流式 API |
SSEParser() | 解析原始 SSE | 处理服务器发送事件 |
import { toAsyncIterable } from '@x-oasis/web-stream';
// 使用 fetch 响应
const response = await fetch('/api/stream');
const iterator = toAsyncIterable(response.body!);
for await (const chunk of iterator) {
// 处理每个块
const text = new TextDecoder().decode(chunk);
console.log('接收:', text);
}
真实例子:处理大文件上传
async function processLargeFile(file: File) {
const stream = file.stream();
const iterator = toAsyncIterable(stream);
let totalSize = 0;
for await (const chunk of iterator) {
totalSize += (chunk as Uint8Array).byteLength;
updateProgressBar(totalSize, file.size);
// 处理块
await processChunk(chunk);
}
}
import { PushStream } from '@x-oasis/push-stream';
// 创建你控制的流
async function* dataGenerator() {
const stream = new PushStream<string>();
// 异步生成数据
setTimeout(() => stream.enqueue('data1'), 100);
setTimeout(() => stream.enqueue('data2'), 200);
setTimeout(() => stream.enqueue('data3'), 300);
setTimeout(() => stream.done(), 400);
yield* stream;
}
// 消费流
for await (const data of dataGenerator()) {
console.log('得到:', data);
}
真实例子:轮询 API
import { PushStream } from '@x-oasis/push-stream';
async function* pollAPI(url: string, interval: number) {
const stream = new PushStream<any>();
const id = setInterval(async () => {
try {
const response = await fetch(url);
const data = await response.json();
stream.enqueue(data);
} catch (error) {
stream.error(error);
}
}, interval);
try {
yield* stream;
} finally {
clearInterval(id);
}
}
// 使用
for await (const data of pollAPI('/api/status', 1000)) {
console.log('状态:', data);
}
import { EventStream } from '@x-oasis/event-stream';
// 收集和聚合结果的流
const results = new EventStream<number>();
// 推送值
results.push(10);
results.push(20);
results.push(30);
results.done();
// 获取最终结果
const sum = await results.result();
console.log('总计:', sum); // 可以是所有值的总和
真实例子:收集多个更新
import { EventStream } from '@x-oasis/event-stream';
class DataCollector {
private stream = new EventStream<Data>();
addData(data: Data) {
this.stream.push(data);
}
complete() {
this.stream.done();
}
async getAggregated() {
return this.stream.result();
}
}
// 使用
const collector = new DataCollector();
collector.addData({ id: 1, value: 100 });
collector.addData({ id: 2, value: 200 });
collector.complete();
const total = await collector.getAggregated();
import { parseJsonEventStream, SSEParser } from '@x-oasis/web-stream';
// 从 SSE 流解析 JSON
async function* handleSSE(url: string) {
const response = await fetch(url);
const stream = parseJsonEventStream(response.body!);
for await (const event of stream) {
console.log('事件:', event);
yield event;
}
}
// 使用
for await (const data of handleSSE('/api/events')) {
console.log('数据:', data);
}
真实例子:实时聊天消息
import { parseJsonEventStream } from '@x-oasis/web-stream';
async function streamMessages(chatId: string) {
const response = await fetch(`/api/chat/${chatId}/stream`);
const events = parseJsonEventStream(response.body!);
for await (const message of events) {
displayMessage({
id: message.id,
author: message.author,
text: message.text,
timestamp: new Date(message.timestamp),
});
}
}
// 在组件中
useEffect(() => {
streamMessages(chatId).catch(console.error);
}, [chatId]);
import { toAsyncIterable } from '@x-oasis/web-stream';
// 创建转换管道
async function* transformStream<T, U>(
source: AsyncIterable<T>,
transform: (item: T) => U
): AsyncGenerator<U> {
for await (const item of source) {
yield transform(item);
}
}
// 使用:解析和转换
const response = await fetch('/api/data');
const lines = toAsyncIterable(response.body!);
const parsed = transformStream(lines, (chunk) => {
const text = new TextDecoder().decode(chunk as Uint8Array);
return JSON.parse(text);
});
for await (const data of parsed) {
console.log('已解析:', data);
}
import { PushStream } from '@x-oasis/push-stream';
async function* safeStream<T>(
generator: AsyncGenerator<T>
): AsyncGenerator<T | Error> {
try {
for await (const item of generator) {
yield item;
}
} catch (error) {
yield error as Error;
}
}
// 使用
const stream = new PushStream<number>();
stream.enqueue(1);
stream.enqueue(2);
stream.error(new Error('流错误'));
for await (const item of safeStream(stream)) {
if (item instanceof Error) {
console.error('流错误:', item.message);
} else {
console.log('值:', item);
}
}
import { PushStream } from '@x-oasis/push-stream';
async function* rateLimitedStream<T>(
source: AsyncIterable<T>,
delayMs: number
): AsyncGenerator<T> {
for await (const item of source) {
yield item;
await new Promise((resolve) => setTimeout(resolve, delayMs));
}
}
// 使用:最多每秒处理 1 项
const response = await fetch('/api/items');
const items = toAsyncIterable(response.body!);
const limited = rateLimitedStream(items, 1000);
for await (const item of limited) {
console.log('正在处理:', item);
}
import { PushStream } from '@x-oasis/push-stream';
async function* bufferedStream<T>(
source: AsyncIterable<T>,
bufferSize: number
): AsyncGenerator<T[]> {
let buffer: T[] = [];
for await (const item of source) {
buffer.push(item);
if (buffer.length >= bufferSize) {
yield [...buffer];
buffer = [];
}
}
if (buffer.length > 0) {
yield buffer;
}
}
// 使用:按批处理
const response = await fetch('/api/data');
const items = toAsyncIterable(response.body!);
const batches = bufferedStream(items, 10);
for await (const batch of batches) {
console.log('正在处理批次:', batch.length);
await processBatch(batch);
}
// 始终清理流
for await (const chunk of stream) {
// 如果需要早期中断
if (done) break; // 将触发清理
}
// 处理错误
try {
for await (const item of stream) {
process(item);
}
} catch (error) {
console.error('流错误:', error);
}
// 使用缓冲以提高效率
const batches = bufferedStream(items, 100);
for await (const batch of batches) {
await processBatch(batch); // 更少的往返
}
// 不要忽视流错误
for await (const item of stream) {
// 如果流在迭代中出错呢?
process(item);
}
// 不要将整个流加载到内存中
const allItems = [];
for await (const item of stream) {
allItems.push(item); // 可能是数百万!
}
// 不要在异步流中使用非异步迭代
const items = await Promise.all(stream); // 错!
// ❌ 文件句柄可能泄漏
async function readFile(path: string) {
const file = await open(path);
for await (const line of file) {
processLine(line);
}
// 缺少:file.close()
}
// ✅ 使用 try-finally 或 for-await
async function readFile(path: string) {
const file = await open(path);
try {
for await (const line of file) {
processLine(line);
}
} finally {
await file.close();
}
}
// ❌ 一次加载所有块违反了流的目的
const allChunks = [];
for await (const chunk of stream) {
allChunks.push(chunk);
}
const result = processAll(allChunks); // 现在我们加载了所有内容!
// ✅ 随时处理
for await (const chunk of stream) {
processChunk(chunk);
// 无论流大小如何,内存恒定
}
// ❌ 源生产速度快于消费
for await (const item of fastSource) {
await slowProcess(item); // 项目堆积!
}
// ✅ 实现适当的背压
const limited = rateLimitedStream(fastSource, 100);
for await (const item of limited) {
await slowProcess(item); // 控制步调
}
import { useEffect, useState } from 'react';
import { parseJsonEventStream } from '@x-oasis/web-stream';
function LiveData() {
const [data, setData] = useState([]);
useEffect(() => {
let cancelled = false;
(async () => {
const response = await fetch('/api/stream');
const stream = parseJsonEventStream(response.body!);
for await (const item of stream) {
if (cancelled) break;
setData((prev) => [...prev, item]);
}
})();
return () => {
cancelled = true;
};
}, []);
return <div>{data.map((item) => <div key={item.id}>{item}</div>)}</div>;
}
import fs from 'fs';
import { toAsyncIterable } from '@x-oasis/web-stream';
async function processLargeLog(filePath: string) {
const stream = fs.createReadStream(filePath);
const iter = toAsyncIterable(stream as any);
for await (const chunk of iter) {
const lines = chunk.toString().split('\n');
lines.forEach((line) => processLogLine(line));
}
}
SOC 직업 분류 기준