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

Discord.js:channels.fetch()返回过期数据的技术求助

问题描述

每分钟获取服务器中当前在任意语音频道的所有成员,但channels.fetch()始终返回client.login时刻的旧数据,而非实时数据。尝试过使用channels.fetch()、channels.cache,调整客户端的不同缓存选项,在函数顶部重新获取频道以更新缓存,但均无效。

原代码

import { getConfig } from '../config/config';
import { client } from '../client';
import { CronJob } from 'cron';
import { EmbedBuilder, GuildMember, TextChannel } from 'discord.js';

const checkerVoice = async () => {
  const guild = await client.guilds.fetch(getConfig().guild);

  const log = (await guild.channels.fetch(getConfig().channels.text.log.debug)) as TextChannel;

  const channels = await guild.channels.fetch();
  const voices = channels.filter(
    (channel) => channel.type === 2 && channel.id !== getConfig().channels.voice.afk,
  );

  voices.forEach(async (channel) => {
    const voice = await guild.channels.fetch(channel.id);
    const members = voice.members as unknown as GuildMember[];
    for (const member of members) {
      log.send({
        embeds: [new EmbedBuilder().setDescription(`${channel.id}@${member}}`)],
      });
    }
  });
};

export const voiceCron = new CronJob('* * * * *', checkerVoice);
解决方案

核心问题

guild.channels.fetch()默认只获取频道基础信息,不会同步语音频道内的成员状态。Discord.js中语音频道的成员列表依赖网关事件同步,如果客户端未正确接收VOICE_STATE_UPDATE事件,缓存内的成员数据就不会实时更新。

修复步骤

  1. 开启必要的特权意图
    在Discord开发者门户的应用页面,开启SERVER MEMBERS INTENT和GUILD VOICE STATES特权意图,同时在客户端初始化时配置:

    const client = new Client({
      intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildVoiceStates, // 必须开启此意图
        GatewayIntentBits.GuildMembers // 需获取成员详细信息时开启
      ]
    });
    
  2. 直接使用缓存获取实时成员
    频道缓存会通过网关事件自动更新,无需重复fetch频道。修改checkerVoice函数:

    const checkerVoice = async () => {
      const guild = client.guilds.cache.get(getConfig().guild);
      if (!guild) return;
    
      const logChannel = guild.channels.cache.get(getConfig().channels.text.log.debug) as TextChannel;
      if (!logChannel) return;
    
      // 从缓存过滤有效语音频道
      const voiceChannels = guild.channels.cache.filter(
        channel => channel.type === ChannelType.GuildVoice && channel.id !== getConfig().channels.voice.afk
      );
    
      // 遍历频道与成员,发送日志
      for (const channel of voiceChannels.values()) {
        for (const member of channel.members.values()) {
          await logChannel.send({
            embeds: [new EmbedBuilder().setDescription(`${channel.id}@${member.user.tag}`)]
          });
        }
      }
    };
    
  3. 修正异步遍历问题
    原代码中forEach结合async/await会导致异步操作无序执行,改用for...of可保证执行顺序,同时避免未处理的Promise问题。

关键说明

  • 只要客户端正确接收GUILD_VOICE_STATES意图,语音频道的members缓存会实时更新,无需手动fetch频道同步成员数据。
  • 若需强制刷新频道基础信息,可在fetch时添加force: true参数,但这仍不会同步成员列表,成员数据始终依赖网关事件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:47:21