前端面试笔试题

314 阅读2分钟

const定义的数据可以更改么?

基本数据类型不可以修改

引用数据类型绑定不可变,但内容可以修改,变量指向的内存地址不变,但对象内部属性或数组元素可以修改。

若需完全不可变,可使用 Object.freeze()(浅冻结)或不可变库(如 Immutable.js)

用setTimeout模拟setInterval?

可以使用 setTimeout 递归调用来模拟 setInterval,这样可以更灵活地控制每次执行的间隔,并且避免 setInterval 的一些潜在问题(例如任务执行时间超过间隔时间导致堆积)。

使用 async/await 控制间隔(适用于异步任务)

如果回调函数是异步的(如 fetch 请求),可以用 async/await 确保每次任务完成后再等待:

async function customAsyncInterval(callback, delay) {
  let isRunning = true;
  const stop = () => {
    isRunning = false;
  };
  const run = async () => {
    while (isRunning) {
      await callback(); // 等待回调完成
      await new Promise(resolve => setTimeout(resolve, delay)); // 等待 delay
    }
  };
  run();
  return s

// 使用示例 const stop = customAsyncInterval(async () => {   console.log("执行异步任务");   await new Promise(resolve => setTimeout(resolve, 500)); // 模拟异步操作 }, 1000); // 5 秒后停止 setTimeout(stop, 5000);

------------- | ---------------------------- | | 方法**** | 特点**** | | setInterval | 固定间隔执行,如果任务执行时间 > 间隔,会导致任务堆积 | | setTimeout 模拟 | 每次任务完成后才重新计时,避免堆积,更可控 | | async/await 版 | 适用于异步任务,确保每次任务完成后再等待

每隔5s打印123

function startInterval(callback, delay) {
  let timerId;
  const repeat = () => {
    callback();
    timerId = setTimeout(repeat, delay);
  };
  timerId = setTimeout(repeat, delay); // 首次执行
  return () => clearTimeout(timerId); // 返回清除函数
}
// 使用
const stopPrinting = startInterval(() => {
  console.log("123");
}, 5000);
// 30 秒后停止
setTimeout(() => {
  stopPrinting();
  console.log("已停止");
}, 30000);
import { useEffect, useRef, useState } from 'react';

const usePolling = (apiFn, interval = 10000, immediate = true) => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const pollingRef = useRef(null);
  
  // 执行请求
  const fetchData = async () => {
    if (!apiFn) return;
    setIsLoading(true);
    try {
      const result = await apiFn();
      setData(result);
      setError(null);
    } catch (err) {
      setError(err);
    } finally {
      setIsLoading(false);
    }
  };

  // 启动轮询
  const startPolling = () => {
    if (pollingRef.current) return; // 避免重复启动
    const poll = async () => {
      await fetchData();
      pollingRef.current = setTimeout(poll, interval);
    };
    poll(); // 立即执行一次
  };
  // 停止轮询
  const stopPolling = () => {
    if (pollingRef.current) {
      clearTimeout(pollingRef.current);
      pollingRef.current = null;
    }
  };

  // 组件挂载时自动启动(如果 immediate=true)
  useEffect(() => {
    if (immediate) {
      startPolling();
    }
    return stopPolling; // 组件卸载时自动停止
  }, [apiFn, interval, immediate]);
  return { data, error, isLoading, startPolling, stopPolling };
};
export default usePolling;


import React from 'react';
import usePolling from './usePolling';

// 模拟 API 请求函数
const fetchUserData = async () => {
  const response = await fetch('https://api.example.com/user');
  return response.json();
};

const UserPollingComponent = () => {
  const { data, error, isLoading, startPolling, stopPolling } = usePolling(
    fetchUserData,
    10 * 60 * 1000, // 10分钟
    true // 立即启动
  );
  return (
    <div>
      <h1>用户数据轮询</h1>
      {isLoading && <p>加载中...</p>}
      {error && <p style={{ color: 'red' }}>错误: {error.message}</p>}
      {data && (
        <div>
          <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
      )}
      <button onClick={startPolling}>开始轮询</button>
      <button onClick={stopPolling}>停止轮询</button>
    </div>
  );
};
export default UserPollingComponent;