Deepseek返回数据采用new Map方式的好处

文章类型:Vue

发布者:hp

发布时间:2026-07-01

一:定义

new Map() 用于创建一个键值对集合,它允许任意类型的值作为键或值,且保持插入顺序。与普通对象不同,Map 的键可以是对象、函数甚至 NaN,且天然支持迭代和大小查询,是处理复杂键映射的高效选择

二:数据结构对比

1:map方式

const thinkingTypewriterQueue = new Map<number, string>()

// 操作
thinkingTypewriterQueue.set(messageId, text)    // 设置/更新
thinkingTypewriterQueue.get(messageId)           // 获取
thinkingTypewriterQueue.delete(messageId)        // 删除
thinkingTypewriterQueue.size                     // 大小

2:对象方式

const thinkingTypewriterQueue = {}

// 操作
thinkingTypewriterQueue[messageId] = text        // 设置/更新
thinkingTypewriterQueue[messageId]               // 获取
delete thinkingTypewriterQueue[messageId]        // 删除
Object.keys(thinkingTypewriterQueue).length      // 大小

3:数组方式

const thinkingTypewriterQueue = []

// 操作
thinkingTypewriterQueue.push({id: messageId, text})  // 添加
thinkingTypewriterQueue.find(item => item.id === messageId)  // 查找
thinkingTypewriterQueue = thinkingTypewriterQueue.filter(item => item.id !== messageId)  // 删除
thinkingTypewriterQueue.length                   



三:为什么选择 Map?

1: 性能优势

操作 Map Object Array

查找 O(1) O(1) O(n)

插入 O(1) O(1) O(1)

删除 O(1) O(1) O(n)

遍历 O(n) O(n) O(n)

2: Key 类型安全


// Map 可以使用任何类型作为 key
const messageId = 1234567890  // number 类型

// Map - 保持 number 类型
thinkingTypewriterQueue.set(messageId, "文本")
thinkingTypewriterQueue.get(messageId)  // ✅ 正确查找

// Object - 自动转为 string
const queue = {}
queue[messageId] = "文本"  // key 变成 "1234567890" (string)
queue[messageId]           // 需要确保类型一致

// 可能导致的问题:
queue[1234567890] === queue["1234567890"]  // true,但容易混淆

3:更好的 API


// Map 提供了专门的方法
thinkingTypewriterQueue.has(messageId)      // 检查是否存在
thinkingTypewriterQueue.clear()             // 清空所有
thinkingTypewriterQueue.size                // 获取大小(属性)
thinkingTypewriterQueue.keys()              // 获取所有 key
thinkingTypewriterQueue.values()            // 获取所有 value
thinkingTypewriterQueue.entries()           // 获取所有键值对

// Object 需要借助工具函数
Object.prototype.hasOwnProperty.call(queue, messageId)  // 检查存在
Object.keys(queue).length                               // 获取大小(计算)


4: 遍历更可靠


// Map 的遍历顺序是插入顺序,可预测
for (const [messageId, pendingText] of thinkingTypewriterQueue.entries()) {
  // 按照插入顺序遍历
  // messageId 是 number 类型
  // pendingText 是 string 类型
}

// Object 的遍历顺序不保证(特别是在某些情况下)
for (const key in queue) {
  // key 是 string 类型
  // 顺序可能不稳定
}


四:实际场景分析

1: 多消息并发打字

// 假设同时有 3 条消息在打字
// 消息 ID: 1001, 1002, 1003

// 使用 Map
const queue = new Map()
queue.set(1001, "消息1的文本...")
queue.set(1002, "消息2的文本...")
queue.set(1003, "消息3的文本...")

// 打字机逐个处理
for (const [messageId, pendingText] of queue.entries()) {
  // 快速找到对应的消息对象
  const message = messages.value.find(m => m.id === messageId)  
  
  // 显示部分文本
  message.thinking = (message.thinking || '') + chunk
  
  // 更新队列
  if (remaining.length > 0) {
    queue.set(messageId, remaining)  // O(1) 快速更新
  } else {
    queue.delete(messageId)          // O(1) 快速删除
  }
  
  break  // 每次只处理一个
}

2: 追加文本

// 后端持续返回增量文本
// 第1次:reasoning = "我正在"
// 第2次:reasoning = "思考"
// 第3次:reasoning = "这个问题"

// 每次收到新文本,需要追加到队列中
const enqueueThinkingTyping = (message: ChatMessage, text: string) => {
  // 获取现有文本 - O(1)
  const existing = thinkingTypewriterQueue.get(message.id) || ''
  
  // 追加新文本
  const newText = existing + text
  
  // 更新队列 - O(1)
  thinkingTypewriterQueue.set(message.id, newText)
  
  // 如果用 Array,需要:
  // 1. find 查找对象 - O(n)
  // 2. 更新对象
  // 3. 没有找到则 push - O(1)
}

3: 清理已完成的消息


// 当某条消息的文本显示完成后
const typewriterStep = () => {
  for (const [messageId, pendingText] of thinkingTypewriterQueue.entries()) {
    if (pendingText.length > 0) {
      // ... 处理显示
      
      if (remaining.length === 0) {
        // 已完成,删除 - O(1)
        thinkingTypewriterQueue.delete(messageId)
      }
    } else {
      // 空文本,删除 - O(1)
      thinkingTypewriterQueue.delete(messageId)
    }
  }
  
  // 如果用 Array,删除需要:
  // queue = queue.filter(item => item.id !== messageId)  // O(n)
}

五、Map 的最佳实践

1. 类型定义

// 明确类型,提高代码可读性
const typewriterQueue = new Map<number, string>()
//                                ↑       ↑
//                            messageId  待显示文本

2. 安全访问

// 使用 || '' 提供默认值
const existing = thinkingTypewriterQueue.get(message.id) || ''

// 或者使用 ?? (nullish coalescing)
const existing = thinkingTypewriterQueue.get(message.id) ?? ''

3. 条件判断

// 检查队列是否为空
if (thinkingTypewriterQueue.size > 0) {
  // 有内容,继续打字
}

// 检查某个消息是否在队列中
if (thinkingTypewriterQueue.has(messageId)) {
  // 该消息还有待显示内容
}

4. 清理资源


// 清空整个队列
thinkingTypewriterQueue.clear()
typewriterQueue.clear()

// 或者逐个删除
for (const messageId of thinkingTypewriterQueue.keys()) {
  thinkingTypewriterQueue.delete(messageId)
}

六:总结

✅ O(1) 性能 - 增删改查都很快

✅ 类型安全 - key 可以是任意类型(我们用 number)

✅ API 简洁 - 专门的方法,语义清晰

✅ 顺序保证 - 遍历顺序就是插入顺序

✅ 易于管理 - size 属性,clear 方法等

✅ 适合场景 - 需要通过 ID 快速查找和更新

为什么选择 Map?

评论
0条评论遵守法律,文明用语,共同建设文明评论区

暂无评论,快来发表第一条评论吧~