JavaScript:有没有一种方法可以使用 Promise 从延迟的限速函数中获取返回值

JavaScript: is there a way to get returned values using Promise from a rate-limited function which got delayed

我有一个这样写的限速器函数

function rateLimter(fn, wait) {
  const queue = []
  let isCalled = false

  const schedule = function () {
    const canSchedule = queue.length && !isCalled
    if (canSchedule) {
      isCalled = true
      queue.shift()()
      setTimeout(() => {
        isCalled = false
        schedule()
      }, wait)
    }
  }

  return function (...args) {
    queue.push(fn.bind(this, ...args))
    schedule()
  }
}

当我们不需要 returned 值或提供给 rateLimiter 的函数的响应时它工作正常。

我正在尝试重写此 rateLImiter 以向我们提供响应或 returned 值。我想我可以传递一个回调来获得这样的响应

function rateLimter(fn, wait, getResponse) {
    const queue = []
    let isCalled = false
  
    const schedule = function () {
      const canSchedule = queue.length && !isCalled
      if (canSchedule) {
        isCalled = true
        getResponse(queue.shift()())
        setTimeout(() => {
          isCalled = false
          schedule()
        }, wait)
      }
    }
  
    return function (...args) {
      queue.push(fn.bind(this, ...args))
      schedule()
    }
  }

但是我试图使用 Promise 来获取值。这是我的尝试

function rateLimter(fn, wait) {
  const queue = []
  let isCalled = false

  const schedule = function () {
    const canSchedule = queue.length && !isCalled
    if (canSchedule) {
      return new Promise((resolve) => {
        isCalled = true
        resolve(queue.shift()())
        setTimeout(() => {
          isCalled = false
          schedule()
        }, wait)
      })
    }
  }

  return function (...args) {
    queue.push(fn.bind(this, ...args))
    return schedule()
  }
}

它只对第一次调用有效,但对速率限制函数的任何后续调用不再 return Promise。有人可以试一试吗?我正在测试的例子是

const logMessageLimited = rateLimter2( async (msg, index) => {
  console.log(msg, index)
  return index + 10
}, 1000, getResponse)

for (let i = 0; i < 3; i++) {
    logMessageLimited(`[Message Log] Action (${i}) rate limited.`, i).then(console.log) // should log out `10` , `11`, `12` 
}

我相信这可以满足您的需求。它与您的原始方法基本相同,只是我们 return 一个承诺并另外将承诺的 resolve 处理程序存储在队列中。

function rateLimter(fn, wait) {
  const queue = []
  let isCalled = false

  const schedule = function () {
    const canSchedule = queue.length && !isCalled
    if (canSchedule) {
      isCalled = true
      const [fn, resolve] = queue.shift()
      resolve(fn())
      setTimeout(() => {
        isCalled = false
        schedule()
      }, wait)
    }
  }

  return function (...args) {
    return new Promise(resolve => {
      queue.push([fn.bind(this, ...args), resolve])
      schedule()
    })
  }
}

const logMessageLimited = rateLimter( async (msg, index) => {
  console.log(msg, index)
  return index + 10
}, 1000)

for (let i = 0; i < 3; i++) {
    logMessageLimited(`[Message Log] Action (${i}) rate limited.`, i).then(console.log) // should log out `10` , `11`, `12` 
}

您的方法不起作用,因为您 return 是 schedule 的承诺,但前提是 canScheduletrue(只有第一次调用该函数(在间隔内)。