uniapp 中使用getAPP 创建了全局变量,值是一个类实例,更改属性之后getAPP获取不到最新的值?

uniapp 中使用getAPP 创建了全局变量,值是一个类实例,更改属性之后getAPP获取不到最新的值?

我写了一个限制请求数量的类文件,在getAPP中创建这个实例,然后加入方法,然后再获取请求的数量,数量一直是0,没有更新。

/**
 *@description
 *@author cy
 *@date 2022-10-20 09:52
 **/

export class LimitRequest {
  private limit: number = 1; // 限制并发数量
  private currentSum: number = 0; // 当前发送数量
  private requests: Array<any> = []; // 请求
  constructor(limit: number) {
    this.limit = limit;
    this.currentSum = 0;
    this.requests = [];
  }

  public request(reqFn: Function) {
    if (!reqFn || !(reqFn instanceof Function)) {
      console.error('当前请求不是一个Function', reqFn);
      return;
    }
    this.requests.push(reqFn);
    if (this.currentSum < this.limit) {
      this.run();
    }
  }
  public stop() {
    this.requests = [];
    this.currentSum = 0;
  }
    public getParam() {
        return { currentSum: this.currentSum, requests: this.requests.length };
    }
  async run() {
    try {
      ++this.currentSum;
      const fn = this.requests.shift();
      await fn();
            console.error('this.requests', this.requests.length);
    } catch (err) {
      console.log('Error', err);
    } finally {
      --this.currentSum;
      if (this.requests.length > 0) {
        this.run();
      }
    }
  }
}

加入request方法模拟请求,

    globalData: {
            limitAjax: new LimitRequest(10)
        },

    for (let i = 0; i < 20; i++) {
                getApp().globalData.limitAjax.request(() => {
                    
                    setTimeout(() => {
                        let params = getApp().globalData.limitAjax.getParam();
                        console.error('parma', params);
                    }, 1000)
                })
            }

打印中的request.length 一直是0,这是为什么呢?求助
image.png

阅读 1.1k
avatarAI BotBETA

这个问题发生的原因是JavaScript中的闭包和异步操作。在JavaScript中,函数是一级对象,这意味着函数可以作为其他函数的参数传递,并且可以作为其他函数的返回值。当你在LimitRequest类的request方法中返回一个函数时,这个函数会捕获到request方法执行时的环境,并记住这个环境。这就是所谓的闭包。

在你的代码中,你创建了一个闭包,它引用了LimitRequest类的requests数组。然后你开始在for循环中创建请求,每个请求都是一个闭包。当你在异步函数中(如setTimeout)使用这些闭包时,它们仍然引用了创建它们的上下文,即LimitRequest类的实例。

然而,当你更改LimitRequest实例的状态(如调用stop方法清空requests数组)时,这个状态更改并不会影响到已经创建的闭包。因为闭包已经捕获了request方法执行时的requests数组的状态,而这个状态在闭包创建后就不会再改变。所以,当你尝试获取请求数量时,你看到的是0,因为闭包引用的requests数组仍然是空的。

要解决这个问题,你需要确保在每次请求时都创建一个新的LimitRequest实例,而不是共享同一个实例。这样,每个请求都有自己的状态,不会受到其他请求的影响。

例如,你可以将创建实例的代码移到request方法中:

for (let i = 0; i < 20; i++) {
  getApp().globalData.limitAjax.request(() => {
    const limitAjax = new LimitRequest(10);
    setTimeout(() => {
      let params = limitAjax.getParam();
      console.error('parma', params);
    }, 1000);
  });
}

这样,每个闭包都会捕获到它自己的LimitRequest实例的状态,而不是共享同一个实例的状态。这样,你就可以正确地获取到每个请求的参数了。

1 个回答

因为调用 request 时传入的方法没有返回 Promise

for (let i = 0; i < 20; i++) {
  getApp().globalData.limitAjax.request(() => {
    return new Promise((resolve) => {
      setTimeout(() => {
        let params = getApp().globalData.limitAjax.getParam();
        console.error("parma", params);
        resolve();
      }, 1000);
    });
  });
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题