You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Apollo React Native拆分大型GraphQL请求?

解决Apollo React Native请求体过大的拆分方案(WhoseApp通讯录查询场景)

针对你遇到的通讯录手机号批量查询请求被CDN拦截的问题,以下是两种拆分请求的实现方案,同时说明为什么useLazyQuery不是最优选择:

1. 顺序请求实现方案

顺序请求适合对并发数有严格限制的场景,避免触发CDN或后端的限流规则,实现逻辑如下:

步骤:

  • 先将手机号数组按每组50个(可根据CDN限制调整)拆分,用简单的chunk工具函数处理:
const chunkArray = (arr, size) => {
  const chunks = [];
  for (let i = 0; i < arr.length; i += size) {
    chunks.push(arr.slice(i, i + size));
  }
  return chunks;
};
  • 通过ApolloClient实例的query方法,结合async/await循环处理每个分组:
import { useApolloClient } from '@apollo/client';

const checkContactStatuses = async (phoneNumbers) => {
  const client = useApolloClient();
  const chunks = chunkArray(phoneNumbers, 50);
  const allResults = [];

  for (const chunk of chunks) {
    try {
      const { data } = await client.query({
        query: GetPhoneNumberAccountStatus,
        variables: { phoneNumbers: chunk },
      });
      allResults.push(...data.getPhoneNumberAccountStatus);
    } catch (error) {
      // 处理单组请求失败,比如重试或记录错误
      console.error(`Chunk request failed:`, error);
      // 可选:如果某组失败就终止流程,直接抛出错误
      // throw error;
    }
  }

  return allResults;
};
  • 在组件中触发查询,比如用户注册流程中:
useEffect(() => {
  if (userIsRegistering && contactsLoaded) {
    checkContactStatuses(contactPhoneNumbers).then(results => {
      setRegisteredContacts(results);
    });
  }
}, [userIsRegistering, contactsLoaded]);

优势:

  • 严格控制请求发送节奏,降低被限流的风险
  • 错误处理更精细,可针对单组请求做重试逻辑

2. 并行请求实现方案

并行请求能大幅提升查询速度,适合后端和CDN允许一定并发数的场景,实现逻辑如下:

步骤:

  • 同样先拆分手机号数组为分组
  • 使用Promise.all或Promise.allSettled并行发送请求,建议用并发限制工具(如p-limit)控制同时发送的请求数,避免触发限流:
import { useApolloClient } from '@apollo/client';
import pLimit from 'p-limit'; // 需要安装p-limit依赖

const checkContactStatusesParallel = async (phoneNumbers) => {
  const client = useApolloClient();
  const chunks = chunkArray(phoneNumbers, 50);
  const limit = pLimit(5); // 限制同时发送5个请求,可根据实际调整

  // 把每个分组请求包装成受限制的Promise
  const requests = chunks.map(chunk => limit(async () => {
    const { data } = await client.query({
      query: GetPhoneNumberAccountStatus,
      variables: { phoneNumbers: chunk },
    });
    return data.getPhoneNumberAccountStatus;
  }));

  // 等待所有请求完成,合并结果
  const results = await Promise.all(requests);
  return results.flat();
};
  • 如果需要容忍部分请求失败,用Promise.allSettled替代Promise.all,过滤出成功的响应:
const results = await Promise.allSettled(requests);
const successfulResults = results
  .filter(res => res.status === 'fulfilled')
  .map(res => res.value)
  .flat();

优势:

  • 相比顺序请求,查询耗时大幅缩短
  • 利用并发提升用户体验,减少等待时间

为什么不推荐用useLazyQuery批量调用?

useLazyQuery是React Hook,必须遵循Hook规则(只能在组件顶层或自定义Hook中调用),批量循环调用会违反规则,导致组件状态混乱。此外,多个useLazyQuery实例的缓存和状态管理会变得复杂,难以统一处理所有请求的结果和错误,直接使用ApolloClient的query实例方法是更简洁、可控的方案。

内容的提问来源于stack exchange,提问作者OneHandClapping

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 12:25:23