刷刷题50(常见的js数据通信与渲染问题)

1. 如何用 JavaScript 的 Proxy 实现数据的双向绑定?写出关键代码并说明其与 Vue 4.0 的响应式系统的差异。

关键代码实现:

ini 复制代码
// 数据模型
const data = { value: "" };

// 监听数据变化的回调函数集合
const callbacks = new Set();

// 创建 Proxy 代理
const proxy = new Proxy(data, {
  set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver);
    // 触发所有回调(模拟视图更新)
    callbacks.forEach(cb => cb());
    return result;
  }
});

// 视图绑定(假设有一个 input 元素)
const input = document.querySelector("input");
input.addEventListener("input", (e) => {
  proxy.value = e.target.value; // 数据变化触发 Proxy.set
});

// 注册更新视图的回调
callbacks.add(() => {
  input.value = proxy.value; // 数据到视图的绑定
});

与 Vue 4.0 的差异:

  1. 依赖追踪‌:

    • Proxy 实现 ‌:需要手动管理依赖(如示例中的 callbacks),无法自动追踪数据与视图的关联。
    • Vue 4.0 ‌:通过 effecttrack/trigger 实现自动依赖收集,精确更新相关组件。
  2. 性能优化‌:

    • Proxy 实现‌:每次数据变化都会触发所有回调,可能造成不必要的渲染。
    • Vue 4.0‌:使用虚拟 DOM 和异步批处理更新,减少实际 DOM 操作次数。
  3. 数据类型支持‌:

    • Proxy 实现 ‌:对数组的 push/pop 等方法需要额外处理。
    • Vue 4.0‌:重写了数组方法,确保能够触发响应式更新。
  4. 嵌套对象‌:

    • Proxy 实现‌:需要递归代理嵌套对象。
    • Vue 4.0‌:通过惰性代理(按需转换)优化性能。

2. 设计一个 JavaScript 的异步任务调度器,支持任务优先级调度和超时熔断。

关键代码实现:

kotlin 复制代码
class TaskScheduler {
  constructor(concurrency = 2) {
    this.queue = [];
    this.running = 0;
    this.concurrency = concurrency;
  }

  add(task, priority = 0, timeout = 5000) {
    const taskWrapper = {
      task: () => Promise.race([
        task(),
        new Promise((_, reject) => 
          setTimeout(() => reject(new Error("Timeout")), timeout)
        )
      ]),
      priority
    };

    // 按优先级插入队列(数值越大优先级越高)
    const index = this.queue.findIndex(t => t.priority < priority);
    if (index === -1) this.queue.push(taskWrapper);
    else this.queue.splice(index, 0, taskWrapper);
    
    this.run();
  }

  run() {
    while (this.running < this.concurrency && this.queue.length > 0) {
      const { task } = this.queue.shift();
      this.running++;
      task()
        .catch(err => console.error("Task failed:", err))
        .finally(() => {
          this.running--;
          this.run();
        });
    }
  }
}

// 使用示例
const scheduler = new TaskScheduler();
scheduler.add(() => fetch("/api/data"), 2, 3000); // 高优先级
scheduler.add(() => console.log("Low priority task"), 0);

核心特性:

  • 优先级调度‌:通过插入排序实现优先级队列。
  • 超时熔断 ‌:使用 Promise.race 实现任务超时自动拒绝。
  • 并发控制‌:限制同时运行的任务数量。

3. 如何用 JavaScript 的 Intersection Observer 实现无限滚动列表?写出关键代码并说明其性能优化策略。

关键代码实现:

ini 复制代码
let page = 1;
const observer = new IntersectionObserver((entries) => {
  if (entries.isIntersecting) {
    loadMore();
  }
}, { threshold: 0.1 });

// 初始占位元素
const sentinel = document.createElement("div");
document.body.appendChild(sentinel);
observer.observe(sentinel);

async function loadMore() {
  observer.unobserve(sentinel); // 防止重复触发
  const data = await fetch(`/api/items?page=${page++}`).then(res => res.json());
  renderItems(data);
  sentinel.scrollIntoView({ behavior: "smooth" });
  observer.observe(sentinel); // 重新观察
}

性能优化策略:

  1. 虚拟列表 ‌:只渲染可视区域内的元素(如使用 react-window 库)。
  2. 请求防抖‌:确保滚动结束时才触发加载。
  3. 内存管理‌:移除视口外的 DOM 元素。
  4. 缓存策略‌:缓存已加载的数据,避免重复请求。

4. 在 JavaScript 中,如何通过 Web Workers 实现多线程计算?写出关键代码并说明其与主线程的通信机制。

关键代码实现:

主线程代码‌:

javascript 复制代码
const worker = new Worker("worker.js");

// 发送数据到 Worker
worker.postMessage({ type: "CALC", data: 1000000 });

// 接收 Worker 结果
worker.onmessage = (e) => {
  console.log("Result:", e.data.result);
};

// 错误处理
worker.onerror = (err) => console.error("Worker error:", err);

worker.js‌:

javascript 复制代码
self.onmessage = (e) => {
  if (e.data.type === "CALC") {
    const result = heavyCalculation(e.data.data);
    self.postMessage({ result });
  }
};

function heavyCalculation(n) {
  // 模拟耗时计算
  return Array.from({ length: n }, (_, i) => i).reduce((a, b) => a + b);
}

通信机制:

  • 数据传递 ‌:通过 postMessage 传递结构化克隆或 Transferable 对象。
  • 无 DOM 访问‌:Worker 线程无法操作 DOM。
  • 异步通信‌:消息传递是非阻塞的。

5. 如何用 JavaScript 的 WebSocket 实现实时消息推送?写出关键代码并说明其与 HTTP 长轮询的优劣。

关键代码实现:

javascript 复制代码
const socket = new WebSocket("wss://api.example.com/ws");

socket.onopen = () => {
  socket.send(JSON.stringify({ subscribe: "updates" }));
};

socket.onmessage = (e) => {
  console.log("New message:", JSON.parse(e.data));
};

socket.onclose = () => {
  console.log("Connection closed");
};

// 发送消息
document.querySelector("button").addEventListener("click", () => {
  socket.send(JSON.stringify({ message: "Hello" }));
});

对比 HTTP 长轮询:

特性 WebSocket HTTP 长轮询
连接类型 全双工持久连接 半双工,每次请求后关闭
延迟 低(无需频繁握手) 较高(每次请求需要重新建立连接)
服务器推送 支持 需等待客户端轮询
资源消耗 较少(维持单一连接) 较高(频繁连接/断开)
浏览器兼容性 IE10+ 所有浏览器
数据传输效率 高效(无 HTTP 头开销) 较低(每次请求携带完整头信息)

选择建议‌:需要高频双向通信(如聊天室)用 WebSocket;低频场景(如邮件通知)可用长轮询。

相关推荐
大学生小郑3 分钟前
Go语言八股之Mysql事务
mysql·面试
进取星辰14 分钟前
28、动画魔法圣典:Framer Motion 时空奥义全解——React 19 交互动效
前端·react.js·交互
不爱吃饭爱吃菜1 小时前
uniapp微信小程序-长按按钮百度语音识别回显文字
前端·javascript·vue.js·百度·微信小程序·uni-app·语音识别
程序员拂雨2 小时前
Angular 知识框架
前端·javascript·angular.js
GoodStudyAndDayDayUp2 小时前
gitlab+portainer 实现Ruoyi Vue前端CI/CD
前端·vue.js·gitlab
程序员阿明2 小时前
vite运行只能访问localhost解决办法
前端·vue
前端 贾公子2 小时前
uniapp -- 验证码倒计时按钮组件
前端·vue.js·uni-app
zhengddzz2 小时前
从卡顿到丝滑:JavaScript性能优化实战秘籍
开发语言·javascript·性能优化
淡笑沐白2 小时前
AJAX技术全解析:从基础到最佳实践
前端·ajax
Go_going_2 小时前
ajax,Promise 和 fetch
javascript·ajax·okhttp