CPPAlien / JS-QA

前端知识问答
0 stars 0 forks source link

如何实现全局同步? #26

Open CPPAlien opened 4 years ago

CPPAlien commented 4 years ago

我们知道可以用 async await 实现一个函数内的同步执行,如

async function test()  {
  await run();
}

但这并不是全局的同步,因为 JS 是单线程,语言中也没有一个线程锁的概念,如果我们有如下需求,

let tag;
async function test() {
  if (tag) {
     tag = await 一个请求,请求成功后,会把 tag 变为 true
     console.log(tag)
  } else {
     console.log(tag)
  }
}

大致意思,是想全局请求一个标志记录,而一旦内存中已经有这个 tag 了就不需要重复请求了。

如果此时外部有多个回掉同时调用的话,会导致 tag 并不是全局唯一生成的,不同回调都会卡在 await 那边,跳过 tag 判断。 request1(() => {test()}) request2(() => {test()})

如何实现全局同步

const PENDDING_LIST: (() => Promise<any>)[] = [];
let timeOutContext: any;
async function test() {
  const promise = () => {
    if (tag) {
      tag = await 一个请求,请求成功后,会把 tag 变为 true
      console.log(tag)
    } else {
       console.log(tag)
    }
 }

GLOBAL_PENDDING_LIST.push(promise);
  clearTimeout(timeOutContext);
  timeOutContext = setTimeout(() => {
    const penddingList: any = [];
    GLOBAL_PENDDING_LIST.map(item => {
      penddingList.push(item);
    });
    GLOBAL_PENDDING_LIST.length = 0;
    const total = penddingList.length;
    let count = 0;
    const run = () => {
      penddingList[count]().then(() => {
        count++;
        if (count >= total) {
          return;
        }
        run();
      });
    };
    run();
  }, 500);
}

首先把执行包装为 promise 的函数,调用后都放到一个队列中。使用一个 timeout 来执行队列中的 promise,因为会该函数会多次执行,为了只执行最后一次 timeout,需要先 clear 老的,再创建。