【问题标题】:Promise values being pushed into array in wrong order承诺值以错误的顺序推入数组
【发布时间】:2020-04-25 20:30:40
【问题描述】:

我正在尝试将值推送到数组中,但是这些值以错误的顺序推送。

//Returns ongoing stream of the decibels in the room 
async getNoise() {
  let subscription = this.dbMeter.start().subscribe(data => {
    this.noiseDb = data;
    return data;
  });
}​ //Returns your current location 
getPosition() {
  return new Promise((res, rej) => {
    navigator.geolocation.getCurrentPosition(res, rej);
  });
}

async startTimer() {
  this.interval = setInterval(async() => {

    interface pos {
      coords ? : any,
    }

    var position: pos = await this.getPosition(); // wait for getPosition to complete

    this.getNoise();

    objects.push({
      lat: position.coords.latitude,
      long: position.coords.longitude,
      noise: this.noiseDb
    });
  }, 500);

}

当有 2 秒延迟时,这可以正常工作,但是当有 1 秒延迟或半秒延迟时,如上所示,值会以错误的顺序推送到数组中,并且相同的值用于多个条目.例如,

[{"lat":55.7558,"long":4.4784,"noise":45.58059,"time":"1.01"},
{"lat":55.7558,"long":4.4784,"noise":45.58059,"time":"2.01"}, 
{"lat":55.7558,"long":4.4784,"noise":40.197384,"time":"4.01"}, 
{"lat":55.7558,"long":4.4784,"noise":40.197384,"time":"3.01"}]

我相信我需要使用 Promise.all() 但我不确定如何实现它。谁能帮帮我?

【问题讨论】:

  • this.noiseDb 是什么?为什么打电话给this.getNoise() 时不等待?
  • noiseDb 只是我在开始时初始化的一个变量,每当我等待 this.getNoise() 时,推送到数组的值始终是未定义的
  • 你认为 getCurrentPosition 什么时候会给你一个不同的值?
  • 我们假设用户正在移动,例如跑步或骑自行车。所以每 500 毫秒 getCurrentPosition 应该返回一个不同的值。

标签: javascript arrays promise es6-promise


【解决方案1】:

这是因为异步调用在执行之前不会等待前一个调用完成。这就是为什么它们是异步的。它们通常用于需要时间执行的 IO 操作。每次异步方法不会阻塞线程,而不是等待 0.5-1 秒,因此在异步函数执行期间将进行其他调用(例如:在文件加载时,或获取地理定位浏览器可以顺利更新 UI)。

在您的情况下,您每 500 毫秒调用一次异步函数。正如我之前所说,异步函数不会等待前一个函数完成。因此,如果第二个调用在第一个调用之前执行,您的列表顺序将不正确。要解决这个问题,我建议您编写如下代码:

let running = true;

startTimer() {
  if (!running) return;

  setTimeout(async() => {
    interface pos {
      coords ? : any,
    }

    var position: pos = await this.getPosition(); // wait for getPosition to complete

    this.getNoise();

    objects.push({
      lat: position.coords.latitude,
      long: position.coords.longitude,
      noise: this.noiseDb
    });

    startTimer();
  }, 500);
}

startTimer();

要启动定时器设置running = true,然后调用startTimer()。要停止运行计时器,只需设置running = false

我使用了setTimeout 而不是setInterval,因为只有在获取完当前地理位置后,我才会重新获取下一个地理位置。

【讨论】:

  • 我同意 Misir Jafarov 的根本问题:您正在同步使用异步思维。我强烈反对提议的解决方案:进行异步调用并阻塞所有逻辑直到每个调用都得到解决有什么意义?
  • @adripanico 我没听懂你。我是不是写错了什么?给定的代码没有阻塞逻辑。 setTimeout 也是异步调用。
  • 你打算采用什么解决方案,@adripanico?我尝试了上面给出的解决方案,但是底部的 startTimer() 实际上似乎根本没有运行,因此这些值只被推送到数组中一次。感谢您迄今为止的帮助!
  • 我首先想了解您试图用该代码做什么。请回答我在问题中的评论。
  • 实际上,在有 GPS 的设备中,对 getCurrentPosition 的调用最多可能需要 1 分钟才能解决。
猜你喜欢
  • 2020-02-12
  • 1970-01-01
  • 2018-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
相关资源
最近更新 更多