js 异步并发锁未生效?

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)
  })
})

错误结果截图

clipboard.png

阅读 2.7k
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题