gpt4 book ai didi

javascript - 为 promise 速率限制功能创建有效测试用例的问题

转载 作者:数据小太阳 更新时间:2023-10-29 05:35:08 25 4
gpt4 key购买 nike

我正在尝试为下面的 promiseRateLimit 函数创建一个有效的测试用例。 promiseRateLimit 函数的工作方式是它使用 queue 来存储传入的 promise ,并在它们之间放置一个 delay

import Promise from 'bluebird'

export default function promiseRateLimit (fn, delay, count) {
let working = 0
let queue = []
function work () {
if ((queue.length === 0) || (working === count)) return
working++
Promise.delay(delay).tap(() => working--).then(work)
let {self, args, resolve} = queue.shift()
resolve(fn.apply(self, args))
}
return function debounced (...args) {
return new Promise(resolve => {
queue.push({self: this, args, resolve})
if (working < count) work()
})
}
}

下面是函数的一个例子。

async function main () {
const example = (v) => Promise.delay(50)
const exampleLimited = promiseRateLimit(example, 100, 1)
const alpha = await exampleLimited('alpha')
const beta = await exampleLimited('beta')
const gamma = await exampleLimited('gamma')
const epsilon = await exampleLimited('epsilon')
const phi = await exampleLimited('phi')
}

示例 promise 需要50ms 来运行,promiseRateLimit 函数将只允许1 promise 每个100 毫秒。所以 promise 之间的间隔应该大于 100ms

这是一个有时返回成功有时失败的完整测试:

import test from 'ava'
import Debug from 'debug'
import Promise from 'bluebird'
import promiseRateLimit from './index'
import {getIntervalsBetweenDates} from '../utilitiesForDates'
import {arraySum} from '../utilitiesForArrays'
import {filter} from 'lodash'

test('using async await', async (t) => {
let timeLog = []
let runCount = 0
const example = (v) => Promise.delay(50)
.then(() => timeLog.push(new Date))
.then(() => runCount++)
.then(() => v)
const exampleLimited = promiseRateLimit(example, 100, 1, 'a')
const alpha = await exampleLimited('alpha')
const beta = await exampleLimited('beta')
const gamma = await exampleLimited('gamma')
const epsilon = await exampleLimited('epsilon')
const phi = await exampleLimited('phi')
const intervals = getIntervalsBetweenDates(timeLog)
const invalidIntervals = filter(intervals, (interval) => interval < 100)
const totalTime = arraySum(intervals)
t.is(intervals.length, 4)
t.deepEqual(invalidIntervals, [])
t.deepEqual(totalTime >= 400, true)
t.is(alpha, 'alpha')
t.is(beta, 'beta')
t.is(gamma, 'gamma')
t.is(epsilon, 'epsilon')
t.is(phi, 'phi')
})

我创建了一个 getIntervalsBetweenDates 函数,它简单地比较两个 unix 时间戳并获取日期数组之间的持续时间。

export function getIntervalsBetweenDates (dates) {
let intervals = []
dates.forEach((date, index) => {
let nextDate = dates[index + 1]
if (nextDate) intervals.push(nextDate - date)
})
return intervals
}

问题是上面的测试有时会返回一个低于 delay 的间隔。例如,如果 delay100ms,有时间隔会返回 98ms96ms。没有理由会发生这种情况。

有没有办法让上面的测试100%通过?我试图确保 delay 参数有效,并且 promise 之间至少有那么多时间。

更新时间为 2016 年 12 月 28 日上午 9:20(美国东部时间)

这是完整的测试

import test from 'ava'
import Debug from 'debug'
import Promise from 'bluebird'
import promiseRateLimit from './index'
import {getIntervalsBetweenDates} from '../utilitiesForDates'
import {arraySum} from '../utilitiesForArrays'
import {filter} from 'lodash'

test('using async await', async (t) => {
let timeLog = []
let runCount = 0
let bufferInterval = 100
let promisesLength = 4
const example = v => {
timeLog.push(new Date)
runCount++
return Promise.delay(50, v)
}
const exampleLimited = promiseRateLimit(example, bufferInterval, 1)
const alpha = await exampleLimited('alpha')
const beta = await exampleLimited('beta')
const gamma = await exampleLimited('gamma')
const epsilon = await exampleLimited('epsilon')
const phi = await exampleLimited('phi')
const intervals = getIntervalsBetweenDates(timeLog)
const invalidIntervals = filter(intervals, (interval) => interval < bufferInterval)
const totalTime = arraySum(intervals)
t.is(intervals.length, promisesLength)
t.deepEqual(invalidIntervals, [])
t.deepEqual(totalTime >= bufferInterval * promisesLength, true)
t.is(alpha, 'alpha')
t.is(beta, 'beta')
t.is(gamma, 'gamma')
t.is(epsilon, 'epsilon')
t.is(phi, 'phi')
})

test('using Promise.all with 2 promises', async (t) => {
let timeLog = []
let runCount = 0
let bufferInterval = 100
let promisesLength = 1
const example = v => {
timeLog.push(new Date)
runCount++
return Promise.delay(50, v)
}
const exampleLimited = promiseRateLimit(example, bufferInterval, 1)
const results = await Promise.all([exampleLimited('alpha'), exampleLimited('beta')])
const intervals = getIntervalsBetweenDates(timeLog)
const invalidIntervals = filter(intervals, (interval) => interval < bufferInterval)
const totalTime = arraySum(intervals)
t.is(intervals.length, promisesLength)
t.deepEqual(invalidIntervals, [])
t.deepEqual(totalTime >= bufferInterval * promisesLength, true)
})

test('using Promise.props with 4 promises', async (t) => {
let timeLog = []
let runCount = 0
let bufferInterval = 100
let promisesLength = 3
const example = v => {
timeLog.push(new Date)
runCount++
return Promise.delay(200, v)
}
const exampleLimited = promiseRateLimit(example, bufferInterval, 1)
const results = await Promise.props({
'alpha': exampleLimited('alpha'),
'beta': exampleLimited('beta'),
'gamma': exampleLimited('gamma'),
'delta': exampleLimited('delta')
})
const intervals = getIntervalsBetweenDates(timeLog)
const invalidIntervals = filter(intervals, (interval) => interval < bufferInterval)
const totalTime = arraySum(intervals)
t.is(intervals.length, promisesLength)
t.deepEqual(invalidIntervals, [])
t.deepEqual(totalTime >= bufferInterval * promisesLength, true)
t.is(results.alpha, 'alpha')
t.is(results.beta, 'beta')
t.is(results.gamma, 'gamma')
t.is(results.delta, 'delta')
})


test('using Promise.props with 12 promises', async (t) => {
let timeLog = []
let runCount = 0
let bufferInterval = 100
let promisesLength = 11
const example = v => {
timeLog.push(new Date)
runCount++
return Promise.delay(200, v)
}
const exampleLimited = promiseRateLimit(example, bufferInterval, 1)
const results = await Promise.props({
'a': exampleLimited('a'),
'b': exampleLimited('b'),
'c': exampleLimited('c'),
'd': exampleLimited('d'),
'e': exampleLimited('e'),
'f': exampleLimited('f'),
'g': exampleLimited('g'),
'h': exampleLimited('h'),
'i': exampleLimited('i'),
'j': exampleLimited('j'),
'k': exampleLimited('k'),
'l': exampleLimited('l')
})
const intervals = getIntervalsBetweenDates(timeLog)
console.log(intervals)
const invalidIntervals = filter(intervals, (interval) => interval < bufferInterval)
const totalTime = arraySum(intervals)
t.is(intervals.length, promisesLength)
t.deepEqual(invalidIntervals, [])
t.deepEqual(totalTime >= bufferInterval * promisesLength, true)
})

即使更改了 example,我仍然遇到问题。

[ 99, 98, 105, 106, 119, 106, 105, 105, 101, 106, 100 ]

2 passed
2 failed

using Promise.props with 4 promises

t.deepEqual(invalidIntervals, [])
|
[99]

Generator.next (<anonymous>)

using Promise.props with 12 promises

t.deepEqual(invalidIntervals, [])
|
[99,98]

Generator.next (<anonymous>)

最佳答案

setTimeout(在 Promise.delay 内部使用)不保证准确的时间,它只确保回调被调用不早于 给定的超时到期。实际时间将取决于机器负载、事件循环的速度和 possibly anything else .

事实上,Node.js docs只声明

The callback will likely not be invoked in precisely delay milliseconds. Node.js makes no guarantees about the exact timing of when callbacks will fire, nor of their ordering. The callback will be called as close as possible to the time specified.

在您的测试中会发生的是 Promise.delay(50) 有时需要超过 50 毫秒(不多,但仍然如此),并且与以下日志的差异可能小于 100 毫秒当下一个 Promise.delay(50) 更准时时。

如果您只是立即记录示例 函数的调用时间,而不是在大约 50 毫秒的人为延迟之后,您应该能够减轻这种影响:

const example = v => {
timeLog.push(new Date);
runCount++;
return Promise.delay(50, v)
};

要处理 100 毫秒超时本身的不准确性,最简单的解决方案是给它一些可能为 5% 的余地(在您的情况下为 5 毫秒):

const invalidIntervals = filter(intervals, (interval) => interval < 100 * .95)
t.true(totalTime >= 400 * .95)

如果你想绝对确定延迟永远不会太短,你可以编写自己的函数:

Promise.delayAtLeast = function(delay, value) {
const begin = Date.now()
return Promise.delay(delay, value).then(function checkTime(v) {
const duration = Date.now() - begin;
return duration < delay
? Promise.delay(delay - duration, v).then(checkTime);
: v;
});
};

并在 promiseRateLimit 中使用它。

关于javascript - 为 promise 速率限制功能创建有效测试用例的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41293841/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com