在异步函数中使用setTimeout

24

我有一个异步函数,它在继续执行之前等待axios调用完成。问题是我需要在axios调用上设置一个超时时间为半秒钟,这样我就不会触发 shopify 的 API 限制。

async function processMatchingSchools(customer_metafield_url) {
  for (const item of customer_metafield_url) {
    await axios.get(item).then((res) => {
      for (key in res.data.metafields) {
        if (res.data.metafields[key].value === schoolName) {
          id_for_each_student.push(shopifyAdmin + "/customers/" + res.data.metafields[key].owner_id + "/metafields.json")
        }
      }
    })
  }
  console.log("Customer metafields to search", id_for_each_student)
  processOwnerIds(id_for_each_student)
}

当我尝试使用setTimeout时,它会调用setTimeout并在完成axios调用之前继续执行。

async function processMatchingSchools(customer_metafield_url) {
  for (const item of customer_metafield_url) {
    await setTimeout(function(item) {
      axios.get(item).then((res) => {
        for (key in res.data.metafields) {
          if (res.data.metafields[key].value === schoolName) {
            id_for_each_student.push(shopifyAdmin + "/customers/" + res.data.metafields[key].owner_id + "/metafields.json")
          }
        }
      })
    }, 500)
  }
  console.log("Customer metafields to search", id_for_each_student)
  processOwnerIds(id_for_each_student)
}

需要帮忙吗?


1
嗯,setTimeout不是基于承诺的,所以尝试等待它有点奇怪。 - Taplar
6个回答

42

await 仅适用于 promises。 您需要将 setTimeout 包装在一个 promise 中:

const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay));

await waitFor(500);

26

setTimeout() 不返回 Promise,但你可以像这样将其包装在一个 Promise 中。我还稍微整理了一下你的代码。

async function processMatchingSchools(customer_metafield_url) {
  for (const item of customer_metafield_url) {
    await new Promise(resolve => {
      setTimeout(resolve, 500)
    })

    const { data: { metafields } } = await axios.get(item)

    for (const { value, owner_id } of Object.values(metafields)) {
      if (value === schoolName) {
        id_for_each_student.push(`${shopifyAdmin}/customers/${owner_id}/metafields.json`)
      }
    }
  }

  console.log("Customer metafields to search", id_for_each_student)

  processOwnerIds(id_for_each_student)
}

2
感谢大家的帮助 :P 还要感谢 Patrick 帮我整理我的新手代码。 - Matthew Werdean

9

setTimeout方法不返回Promise,因此无法使用await等待其完成。

您可以创建自己的基于Promise的setTimeout并使用它。

const setTimeoutPromise = timeout => new Promise(resolve => {        
  setTimeout(resolve, timeout);
});

await setTimeoutPromise(500);

6
创建一个 sleep 函数,它返回一个 Promise,你可以像这样使用它:
const sleep = (milliseconds=500) => new Promise(resolve => setTimeout(resolve, milliseconds))

并在异步函数中使用它:

(async () => {
  console.log("function invoked...")
  await sleep(500)
  console.log("I got here about 500 milliseconds later")
})()

const sleep = ms => {return new Promise(resolve => setTimeout(resolve, ms));} 请注意,此为程序开发相关内容,请勿误解。 - arielhasidim

4

你需要创建一个新的 Promise,例如像这样:

function delay(ms){
 return new Promise(resolve => setTimeout(resolve, ms))
}

然后在调用API之前,在您的代码中使用它

...
await delay(500)
await axios.get(item).then((res) => {
...

3
我创建了一个名为setTimeout2的函数,它的工作原理与Promise相同:
const setTimeout2 = (callback, ms) => {
  return new Promise(resolve => setTimeout(() => {
    callback();
    resolve();
  }, ms));
} 

因此,总的来说(注意setTimeout2的变化):

async function processMatchingSchools(customer_metafield_url) {
  for (const item of customer_metafield_url) {
    await setTimeout2(function(item) {
      axios.get(item).then((res) => {
        for (key in res.data.metafields) {
          if (res.data.metafields[key].value === schoolName) {
            id_for_each_student.push(shopifyAdmin + "/customers/" + res.data.metafields[key].owner_id + "/metafields.json")
          }
        }
      })
    }, 500)
  }
  console.log("Customer metafields to search", id_for_each_student)
  processOwnerIds(id_for_each_student)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接