js 异步并发锁未生效?
场景
今天尝试自己写了一个 js 的限制同时存在异步数量的并发锁,然而测试了一下并未生效,不知道为什么 this.limit
的值在 wait
中一直拿到的都是 1
代码
import { wait } from '../function/wait'
/**
* 默认的超时时间,可以认为是无限
*/
const TimeoutInfinity = () => false
/**
* 创建一个 Lock 对象,用于锁住当前的当前的异步流程
*/
export class Locker {
constructor ({ limit = 1, timeout = TimeoutInfinity } = {}) {
this.limit = limit
this.timeout = timeout
}
/**
* 当前是否锁住了
*/
isLocked () {
return this.limit <= 0
}
/**
* 添加异步锁
* @param {Number} timeout 超时时间
*/
// @ts-ignore
async lock (timeout = this.timeout) {
if (this.isLocked()) {
/**
* @type {Number|Function}
*/
await Promise.race([wait(() => !this.isLocked()), wait(timeout)])
}
this.limit--
}
/**
* 删除异步锁
*/
unlock () {
this.limit++
}
}
引用的代码
/**
* 等待指定的时间/等待指定表达式成立
* 如果未指定等待条件则立刻执行
* @param {Number|Function} [param] 等待时间/等待条件
* @returns {Promise} Promise 对象
*/
export const wait = param => {
return new Promise(resolve => {
if (typeof param === 'number') {
setTimeout(resolve, param)
} else if (typeof param === 'function') {
const timer = setInterval(() => {
if (param()) {
clearInterval(timer)
resolve()
}
}, 100)
} else {
resolve()
}
})
}
/**
* 创建一个等差数列数组
* @param {Number} start 开始(包含)
* @param {Number} end 结束(不包含)
* @param {Number} [sep] 步长,默认为 1
* @returns {Array.<Number>} 等差数列数组
*/
export function range (start, end, sep = 1) {
const arr = []
for (let i = start; i < end; i += sep) {
arr.push(i)
}
return arr
}
测试代码
import { wait } from '../function/wait'
import { Locker } from './Locker'
import { range } from '../array/range'
/**
* @test {Locker}
*/
describe('test Locker', () => {
it('simple example', async () => {
const locker = new Locker()
// 模拟异步请求,需要 300ms
const fn = async () => {
try {
// 加锁
await locker.lock()
await wait(300)
} finally {
// 释放锁
locker.unlock()
}
}
// 计算 10 次请求需要的时间,期待应该是 3000ms
const start = Date.now()
// 使用 Promise.all 模拟并发请求 10 次
await Promise.all(range(0, 10).map(fn))
expect(Date.now() - start).toBeGreaterThan(3000)
})
})
错误结果截图