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

什么是流式数据处理?

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

微信小程序中的实现方案

微信小程序通过 wx.request 的 rsponseType:"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 解析器安装:

bash 复制代码
yarn add markdown-it
相关推荐
毕设源码-赖学姐1 小时前
【开题答辩全过程】以 赣农乐微信小程序为例,包含答辩的问题和答案
微信小程序·小程序
一 乐4 小时前
远程在线诊疗|在线诊疗|基于java和小程序的在线诊疗系统小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·小程序
2501_915918414 小时前
HTTP和HTTPS工作原理、安全漏洞及防护措施全面解析
android·http·ios·小程序·https·uni-app·iphone
2501_916007475 小时前
如何在 Windows 电脑上调试 iOS 设备上的 Safari?完整方案与实战经验分享
android·windows·ios·小程序·uni-app·iphone·safari
2501_915918416 小时前
uni-app iOS日志管理实战,从调试控制台到系统日志的全链路采集与分析指南
android·ios·小程序·https·uni-app·iphone·webview
毕设源码-钟学长6 小时前
【开题答辩全过程】以 二手小型电子产品商城小程序为例,包含答辩的问题和答案
小程序
hdsoft_huge6 小时前
小程序弱网 / 无网场景下 CacheManager 离线表单与拍照上传解决方案
java·小程序·uni-app
Jerry2505096 小时前
微信小程序必要要安装SSL证书吗?小程序SSL详解
网络·网络协议·网络安全·微信小程序·小程序·https·ssl
WKK_6 小时前
uniapp小程序 订阅消息推送
小程序·uni-app
万岳科技程序员小金6 小时前
多端统一的教育系统源码开发详解:Web、小程序与APP的无缝融合
前端·小程序·软件开发·app开发·在线教育系统源码·教育培训app开发·教育培训小程序