nbhaohao/javascript-notes

Promise 串行面试题

Opened this issue · 0 comments

问题

我们有 A, B 两个按钮,A 会发送一个请求,向服务端拿取数据,B 也会发送一个请求,向服务器拿取数据。

我们先点击 A, 再点击 B. 正常的表现是这样的:(这时候 A 的请求要花 500 毫秒,B 的请求要花 800 毫秒)

Oct-05-2019 19-15-31

因为我们先点击 A 按钮,再点击 B 按钮,所以我们期待最后显示的是 B 的结果。

但是假如我们的操作不变,如果 A 请求的时间要比 B 请求的时间要久,即我们先点击 A 按钮,再点击 B 按钮,然后 B 的请求先返回了,然后再返回 A 的请求,Bug 就出现了。

bug

由于我们后点击的 B 按钮,所以我们希望看到 B 按钮所请求到的内容,但是 A 请求的比较慢,所以它把内容覆盖掉了。

目前我们的代码如下:

  <body>
    <span>返回结果: <span id="result"></span></span>
    <div></div>
    <button id="buttonA">A</button>
    <button id="buttonB">B</button>
  </body>
const ajaxA = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("结果A");
    }, 2000);
  });
};
const ajaxB = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("结果B");
    }, 1000);
  });
};
const changeResult = msg => {
  document.querySelector("#result").innerHTML = msg;
};
const testA = async () => {
  const result = await ajaxA();
  changeResult(result);
};
const testB = async () => {
  const result = await ajaxB();
  changeResult(result);
};
buttonA.onclick = testA;
buttonB.onclick = testB;

解法

我们需要 2 个队列,第一个队列用来记录发送请求的顺序,第二个队列用来存储请求的结果,第二个队列一旦产生结果,他需要检查一下,是不是属于第一个队列中先发的请求的,如果是,那么就显示,如果不是,那么就把这个请求结果先存起来,因为暂时用不到。

const requestArray = [];
const responseArray = [];

const ajaxA = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("结果A");
    }, 2000);
  });
};
const ajaxB = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("结果B");
    }, 1000);
  });
};
const changeResult = msg => {
  document.querySelector("#result").innerHTML = msg;
};
const handleResponse = () => {
  if (requestArray.length === 0) {
    return;
  }
  const eraliestRequest = requestArray[0];
  const responseItemIndex = responseArray.findIndex(
    item => item.tag === eraliestRequest.tag
  );
  if (responseItemIndex === -1) {
    return;
  }
  eraliestRequest.callback(responseArray[responseItemIndex].result);
  requestArray.shift();
  responseArray.splice(responseItemIndex, 1);
  handleResponse();
};
const testA = async () => {
  const tag = `${Date.now()}-testA`;
  requestArray.push({
    tag,
    callback: result => {
      console.log("执行 tagA 的回调");
      changeResult(result);
    }
  });
  const result = await ajaxA();
  responseArray.push({
    tag,
    result
  });
  handleResponse();
};
const testB = async () => {
  const tag = `${Date.now()}-testB`;
  requestArray.push({
    tag,
    callback: result => {
      console.log("执行 tagB 的回调");
      changeResult(result);
    }
  });
  const result = await ajaxB();
  responseArray.push({
    tag,
    result
  });
  handleResponse();
};
buttonA.onclick = testA;
buttonB.onclick = testB;