微信小程序 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
相关推荐
流***陌6 小时前
扭蛋机 Roll 福利房小程序前端功能设计:融合趣味互动与福利适配
前端·小程序
亮子AI10 小时前
【小程序】微信小程序点击效果(view、button、navigator)
微信小程序·小程序
Q_Q51100828510 小时前
python+uniapp基于微信小程序团购系统
spring boot·python·微信小程序·django·uni-app·node.js·php
future_studio10 小时前
聊聊 Unity(小白专享、C# 小程序 之 加密存储)
开发语言·小程序·c#
炒毛豆11 小时前
uniapp微信小程序+vue3基础内容介绍~(含标签、组件生命周期、页面生命周期、条件编译(一码多用)、分包))
vue.js·微信小程序·uni-app
從南走到北11 小时前
洗车小程序系统
微信小程序·小程序
namehu12 小时前
前端性能优化之:图片缩放 🚀
前端·性能优化·微信小程序
dazhong201212 小时前
微信小程序开发实战指南(三)-- Webview访问总结
微信小程序·小程序
计算机毕业设计小帅13 小时前
【2026计算机毕业设计】基于Springboot的校园失物招领小程序
spring boot·小程序·课程设计
盛夏绽放15 小时前
关于 uni-app 与原生微信小程序中的生命周期 —— 一次“生命旅程”的解读
微信小程序·小程序·uni-app