要是实在不知道要干什么,那就喝两杯思路就来了!

导航菜单

记一次高德手写面试题

轮询是前端开发过程当中经常会遇到,它是一种模拟服务器主动推送消息的场景。在一次高德面试题中给定两个 async 函数,让使用前端代码模拟轮询查询的场景,当时还是比较慌得一批的,写了个残次品。二话不说咱们看要求:

// 1. 每隔 3 秒请求一次,成功返回结果,失败继续重试
// 2. 如果请求未在 3秒 内返回,直接超时并继续重试
// 3. 10 秒超时直接返回

const fakeFetch = async (params) => {}
const requestFn = async (params) => {}

最开始想简单了,一顿定时器操作完成之后,被反问了几个问题之后,感觉这个功能涉及考点还真挺多:

1、时间重置问题:fakeFetch 在模拟延时的情况下,只要超过 3 秒就永远查不到结果;

2、异步机制问题:await fakeFetch() 在请求等待过程中,后面的定时器无法启动;

以下是面试结束之后优化的结果,已通过 chrome 测试通过。

const fakeFetch = async (params) => {
    if (!fakeFetch.status) {
      fakeFetch.status = 'prepare'; // 响应状态 prepare: 已就绪, pendding: 响应中
      fakeFetch.timeout = 4000; // 指定接口超时时间
      fakeFetch.data = undefined; // 返回返回数据
    }

    if (fakeFetch.status === 'prepare') {
      fakeFetch.data = await new Promise((resolve, reject) => {
        fakeFetch.status = 'pendding';

        // 模拟接口请求时间
        setTimeout(() => {
          fakeFetch.status = undefined;
          resolve({ status: 200, msg: 'success', data: '这是一堆业务数据' })
        }, fakeFetch.timeout);
      });
    }
    return fakeFetch.data;
};

const requestFn = async (params) => {
  let data, timer1, timer2, times = 1;
  clearInterval(timer1);
  clearTimeout(timer2);

  // 轮询处理
  timer1 = setInterval(async () => {
    if (data) {
      console.log(data); // 成功返回结果
      clearInterval(timer1);
      clearTimeout(timer2);
      return;
    }
    console.log('第 ' + (++times) + ' 次发起请求!');
    data = await fakeFetch(params); // 重试
  }, 3000);

  // 超时处理
  timer2 = setTimeout(() => {
    clearInterval(timer1);
    clearTimeout(timer2);
    console.error('超时'); // 超时
  }, 10000);

  // 发起模拟网络请求
  console.log('第 ' + (times) + ' 次发起请求!');
  data = await fakeFetch(params); // 第一次发起请求
};

requestFn();


发表评论