如何根据异步调用的持续时间设置 JS 变量

How to set a JS variable depending on the duration of an asynchronous call

我有这个:

this.toggleWaiting()
this.results = await this.query(term)
this.toggleWaiting()

首先触发加载微调器。 然后查询运行。 当查询函数结束时,加载微调器将关闭。

但是如果我只想显示加载微调器,当查询可能需要超过 0.5 秒时怎么办?

有没有简单的方法可以做到这一点?

实现此目的的一种方法是将 this.query(term) 承诺传递给一个函数,该函数将仅在查询花费的时间超过指定的时间量(使用超时)时处理触发 toggleWaiting .

例如,下面有一个承诺,一个将以 isWaiting 状态调用的函数 (waitingFn) 以及一个可以用来指定的 timeout在显示加载微调器之前要等待多长时间。最后,当承诺已经实现时,我们 return 结果:

async function handleWaiting(promise, waitingFn, timeout) {
  let loadingStarted = false;
  let timeoutInstance = null;

  const timeoutPromise = new Promise((res) => {
    timeoutInstance = setTimeout(() => {
      loadingStarted = true;
      waitingFn(true);
    }, timeout);
    return res();
  });

  function onFinished() {
    clearTimeout(timeoutInstance);

    if (loadingStarted) {
      waitingFn(false);
    }
  }

  try {
    const [result] = await Promise.all([promise, timeoutPromise]);
    onFinished();
    return result;
  } catch (ex) {
    onFinished();
    throw ex;
  }
}

您可以像这样调用 handleWaiting 函数:

const result = await handleWaiting(this.query(term), (isWaiting) => this.toggleWaiting(), 500);

正如@FZs 和@Bergi 所指出的(谢谢你们),以下是由于使用 promise 构造函数而导致的反模式:

function handleWaiting(promise, waitingFn, timeout) {
  return new Promise((res, rej) => {
     let loadingStarted = false;
   
     const timeoutInstance = setTimeout(() => {
       loadingStarted = true; 
       waitingFn(true);
     }, timeout);

     function onFinished() {
       if (loadingStarted) {
         waitingFn(false);
       }
       clearTimeout(timeoutInstance);
     }
     
     return promise
       .then((result) => {
         onFinished();
         res(result);
       })
       .catch((ex) => {
         onFinished();
         rej(ex);
       });
  });
}

感谢 ljbc1994,我找到了一个很好的解决方案。

在我的 alpineJs 对象中 - 我有这个实现:

{
   waiting: false,

   async handleWaiting(promise, timeout) {
       return new Promise((res, rej) => {
           let loadingStarted = false;

           const timeoutInstance = setTimeout(() => {
               loadingStarted = true;
               this.waiting = true;
           }, timeout);

           const onFinished = () => {
               if (loadingStarted) {
                   this.waiting = false;
               }
               clearTimeout(timeoutInstance);
           }

           promise
               .then((result) => {
                   onFinished();
                   res(result);
               })
               .catch((ex) => {
                   onFinished();
                   rej(ex);
               });
       });
    },

    async searchForTerm(term) {
       this.results = await this.handleWaiting(this.$wire.query(term), 500);
       // do something with the results...
    },
 }

非常简单。

对于对完整代码感兴趣的人 - 这是 github 存储库中的提交:

https://github.com/MichaelBrauner/sunfire-form/commit/7c1f8270e107a97b03264f5ddc5c3c3ae6f7cfd7