如何在Angular 6的循环中链接承诺

Posted

技术标签:

【中文标题】如何在Angular 6的循环中链接承诺【英文标题】:how to chain promises in a loop in Angular 6 【发布时间】:2019-07-23 03:56:56 【问题描述】:

我正在尝试使用名为 addDevice() 的函数更新本地存储,它会检查密钥中是否已经存在一些数据,然后将其附加到其他内容中,只需更新密钥即可。

export class DeviceService implements devicesInterface 

  devices : Array<deviceInterface> = [];  

  constructor(private storage : Storage, private http : HttpClient)  

    addDevice(ssid : String, name : String)
      console.log("add device called "+ssid +name)
      return this.getDevices().then((res : devicesInterface) => 
        console.log("res");
        console.log(res)
        if (res) 

          this.devices = res.devices;
          console.log(res);
          this.devices.push( ssid: ssid, name: name );
          return this.storage.set(TOTAL_DEVICES,  devices: this.devices );
        
        else 
          console.log("not res");
          let devices_obj =  devices: [ ssid: ssid, name: name ] ;
          return this.storage.set(TOTAL_DEVICES, devices_obj);
        
      )     
  


  getDevices()
    return this.storage.get(TOTAL_DEVICES)
  

从页面中,我调用了一个 API,它解析为 deviceInterface 类型的数组。

  this.deviceService.getDevicesFromServer(this.authenticationService.getToken())
        .subscribe((res : Array<deviceInterface>) =>
            if(res)
              this.storage.remove("TOTAL_DEVICES")
              this.devices = []
            

            res.map(async device => 
              await this.deviceService.addDevice(device.ssid, device.name).then(res=>
                console.log("device added..")
                this.devices.push(device)
                console.log(res)
              )
            );
          )

addDevice 函数必须在链中调用,这样下次调用时它会获取数据并追加,如果异步调用此函数,数据将被一次又一次地覆盖。

我已经搜索了很多但没有找到任何与我的问题相匹配的相关解决方案,我如何在 res 对象上链接迭代并在最后一次调用解决后调用 addDevice 函数。

【问题讨论】:

您确定您的地图功能正在做您认为的事情吗?看看这个答案***.com/a/37576787/4553162,看看你不能真正做一个这样的循环,并期望它等待每次迭代完成,然后再触发下一次对addDevice的调用 一点代码可能会有很大帮助,我认为 map 不应该用作迭代器。 当然,我将添加一个示例作为我建议的答案 【参考方案1】:

您从 addDevice() 方法返回了错误的承诺。返回 setter 承诺而不是 getter 承诺

addDevice(ssid : String, name : String)
  console.log("add device called "+ssid +name);

  return new Promise((resolve, reject) => 
    this.getDevices().then((res : devicesInterface) => 
      console.log("res");
      console.log(res);

      if (res) 
        this.devices = res.devices;
        console.log(res);
        this.devices.push( ssid: ssid, name: name );
        this.storage.set(TOTAL_DEVICES,  devices: this.devices ).then(resolve).catch(reject);
      
      else 
        console.log("not res");
        let devices_obj =  devices: [ ssid: ssid, name: name ] ;
        this.storage.set(TOTAL_DEVICES, devices_obj).then(resolve).catch(reject);
      
    );
  );   

【讨论】:

我更新了 addDevice 方法以按照您的建议返回 setter 承诺,但同样的问题循环运行得如此之快,不要等待承诺解决,然后再运行另一个承诺并导致执行 else 案例每次添加设备【参考方案2】:

我认为您的 map 函数不会等待每次迭代完成,因此结果会被覆盖。你可以试试:

for (const device of res) 
    await this.deviceService.addDevice(device.ssid, device.name)
    .then(res => 
            console.log("device added..")
            this.devices.push(device)
            console.log(res)
    )

更多详情见https://***.com/a/37576787/4553162

【讨论】:

这行得通,这是使用 await 的正确语法,在使用 map 之前,我尝试了每个都没有运气。也必须在 .subscribe(async 之后立即使用 aysnc

以上是关于如何在Angular 6的循环中链接承诺的主要内容,如果未能解决你的问题,请参考以下文章

Angular forEach 等到所有承诺都完成?

如何在 knex.js 迁移中链接承诺

如何在 Angular 1.5 组件中等待来自 UI Router Resolve 的承诺

在 for 循环中链接猫鼬承诺

在 ngOnInit Angular 之前处理异步承诺

如何在 Angular 6 中使用 angular-timelinejs3?