微信小程序 request 流式数据处理

什么是流式数据处理?

流式数据处理(Streaming Data)指逐步接收并处理数据片段的技术,无需等待全部数据加载完成。适用于大文件下载、实时日志、AI生成报告等场景,可显著降低内存占用并提升用户体验。

微信小程序中的实现方案

微信小程序通过 wx.requestresponseType: "arraybuffer" 返回二进制数据,enableChunked 配置启用分块传输,配合 onChunkReceived 回调实现流式处理。

通用方法封装

javascript 复制代码
/**
 * 流式请求封装
 * @param {string} url 请求地址
 * @param {Object} data 请求参数
 * @param {Function} onProgress 分块数据处理回调
 * @param {Object} headers 自定义请求头
 */
export function streamRequest({ url, data, onProgress, headers }) {
  return new Promise((resolve, reject) => {
    wx.request({
      url,
      data,
      header: headers || {},
      responseType: "arraybuffer", // 关键:接收二进制流
      enableChunked: true, // 启用分块传输
      success(res) {
        if (res.statusCode === 200) resolve(res);
      },
      fail(err) {
        reject(err)
      },
      onChunkReceived(response) {
        // 每次收到分块时触发
        const chunk = response.data; // 获取二进制数据块
        try {
          // 将ArrayBuffer转为可读字符串
          const textDecoder = new TextDecoder('utf-8');
          const chunkStr = textDecoder.decode(chunk); // data:{"done":false,"response":"异常"} data:{"done":false,"response":","} data:{"done":false,"response":"建议"} data:{"done":false,"response":"结合"}
          // 根据需要做后续处理
          onProgress?.(chunkStr);
        } catch (e) {
          console.error('Chunk parsing failed:', e);
        }
      }
    });
  });
}

使用示例:AI生成报告解读实时解析

html 复制代码
<template>
  <view class="page">
    <scroll-view
      class="ai-content"
      scroll-y
      style="max-height:calc(100vh - {{navHeight}}px);"
      enable-back-to-top
      scroll-top="{{scrollTop}}"
      bindscroll="scroll"
      :scroll-with-animation="false"
      bindscrolltolower="next"
    >
      <view bindtap="getAIReportDecode">开始生成</view>
      <view>
        <van-loading wx:if="{{loading}}"/>
        <view>
          <span>报告智能解读:</span>
          <rich-text nodes="{{result}}"></rich-text>
        </view>
      </view>
    </scroll-view>
  </view>
</template>
javascript 复制代码
<script>
import { Page } from "@wxa/core";
import { streamRequest } from "../../../../static/utils/index.js";

const MarkdownIt = require('markdown-it');
const md = new MarkdownIt();

var that, $data;

@Page
export default class Index {
  data = {
    result: "",
    loading: true,
    scrollTop: 0,
    isAutoScrolling: true, // 是否自动滚动
    word: "",
    targetScrollTop: 0,
    requestTask: null
  };

  async onLoad(e) {
    that = this;
    $data = that.data;
  }

  onUnload() {
    if ($data.requestTask) {
      $data.requestTask.abort();
    }
  }
  getAIReportDecode() {
    streamRequest({
      url: "https://api.example.com/ai/report",
      data: {},
      onProgress(res) {
        const messages = res.trim().split("\n\n");
        const parsedMessages = messages
          .map(message => {
            // 按 "data:" 拆分,取后面的部分
            const dataPart = message.split("data:")[1];
            if (dataPart) {
              // 解析 JSON 字符串并返回对象
              return JSON.parse(dataPart.trim());
            }
          })
          .filter(v => {
            return v;
          }); // 过滤掉异常值
        const line = parsedMessages.map(v => {
          return v.response;
        });
        line.forEach(v => {
          $data.word += line;
          that.setData({ result: md.render($data.word) });
          that.autoScrollToBottom();
        });
      }
    }).then(() => {
      console.log("报告接收完成");
    });
  }

  scroll(e) {
    if ($data.targetScrollTop > 0) {
      return; // 忽略此次滚动事件
    }
    const { scrollTop, scrollHeight } = e.detail;
    const query = wx.createSelectorQuery();
    query
      .select(".ai-content")
      .boundingClientRect(rect => {
        if (rect) {
          const clientHeight = rect.height;
          if (scrollTop + clientHeight < scrollHeight) {
            that.setData({ isAutoScrolling: false });
          }
        }
      })
      .exec();
  }

  next() {
    that.setData({
      targetScrollTop: 100
    });
    that.setData({ isAutoScrolling: true });
    setTimeout(() => {
      that.setData({
        targetScrollTop: 0 // 重置目标 scrollTop
      });
    }, 100);
  }

  autoScrollToBottom() {
    if (!$data.isAutoScrolling) return;

    const query = wx.createSelectorQuery();
    query
      .select(".ai-content")
      .boundingClientRect(rect => {
        that.setData({
          scrollTop: rect.height * 100,
          targetScrollTop: 100
        });
        setTimeout(() => {
          that.setData({
            targetScrollTop: 0 // 重置目标 scrollTop
          });
        }, 100);
      })
      .exec();
  }
}
</script>
javascript 复制代码
<config>
{
  "usingComponents": {
    "van-loading": "@vant/weapp/loading/index"
  }
}
</config>

Markdown 解析器安装:yarn add markdown-it

相关推荐
hunzi_19 小时前
选择网上购物系统要看几方面?
java·微信小程序·小程序·uni-app·php
2305_7978820912 小时前
AI识图小程序的功能框架设计
人工智能·微信小程序·小程序
暮雨哀尘13 小时前
微信小程序开发:开发实践
开发语言·算法·微信小程序·小程序·notepad++·性能·技术选型
幽络源小助理15 小时前
微信小程序实验室管理SSM系统设计与实现
微信小程序·小程序
人人题1 天前
汽车加气站操作工考试答题模板
笔记·职场和发展·微信小程序·汽车·创业创新·学习方法·业界资讯
曲江涛1 天前
微信小程序 webview 定位 并返回
微信小程序·小程序
weixin_440470501 天前
部署Dify接入微信验证反代根目录创建一个文件通过微信小程序验证
微信小程序·腾讯云
web_Hsir1 天前
uniapp 微信小程序 使用ucharts
微信小程序·小程序·uni-app
web_Hsir1 天前
Uniapp 实现微信小程序滑动面板功能详解
vue.js·微信小程序·uni-app