【问题标题】:How to call one asynchronous function after another?如何一个接一个地调用一个异步函数?
【发布时间】:2020-09-17 07:28:12
【问题描述】:

这就是我所拥有的:

  ngOnInit() {
    this._addServ.getDefaultAddress().subscribe((res)=>{
      if(res.status){
        //I need these next two functions to finish their async API requests 
        //before selectNormalDelivery is called
        this.selectShippingAddress();
        this.selectBillingAddress();
        this.selectNormalDelivery();
      }
    })
  }

我需要selectShippingAddressselectBillingAddress 来完成他们的通话,然后才能调用selectNormalDelivery。我怎样才能做到这一点?我不想将它们转换为承诺,因为它们在其他时候被调用而无需被链接。这是否涉及.then

这是函数的代码:

  selectShippingAddress(){
    this.addressService.setShippingAddresses(this.cartService.shippingAddress.address_id).subscribe((res) => {
      console.log('Set shipping address!')
      console.log(res);
    }, err => {
      console.log('Failed to set shipping address')
      console.log(err);
    })
  }

  selectBillingAddress(){
    this.addressService.setPaymentAddresses(this.cartService.billingAddress.address_id).subscribe((res) => {
      console.log('Set billing address!')
      console.log(res);
    }, err => {
      console.log('Failed to set billing address')
      console.log(err);
    })
  }

如果我尝试.then,我会收到错误Property 'then' does not exist on type 'void'.,这是有道理的,因为我没有尝试返回任何内容,我只需要他们为了 API 的缘故完成他们的调用。

建议?

【问题讨论】:

  • 那么你需要改变那些函数来返回一些东西:一个承诺,如果你想使用.then;或可观察的。或者他们可以接受回调,但添加另一个异步范例可能不是一个好主意。
  • 嗯,我对创建和订阅自定义 observables 不是很熟悉。我也可以尝试使用相同组件事件发射器的方法吗?并且功能可以相互倾听?
  • 我建议您阅读一下,然后,它是 Angular 处理大多数异步事情方式的重要组成部分。
  • 这可能会对您有所帮助。 stackoverflow.com/questions/49596641/…
  • 在下面查看我的解决方案。

标签: javascript angular asynchronous callback


【解决方案1】:
ngOnInit() {
    this._addServ.getDefaultAddress().subscribe((res)=>{
      if(res.status){
        //I need these next two functions to finish their async API requests 
        //before selectNormalDelivery is called
        forkJoin([this.selectShippingAddress(),this.selectBillingAddress()].subscribe(() => {

            this.selectNormalDelivery();
        });
      }
    })
  }

 selectShippingAddress(){
    return this.addressService.setShippingAddresses(this.cartService.shippingAddress.address_id).pipe(map((res) => {
      console.log('Set shipping address!')
      console.log(res);
    }, err => {
      console.log('Failed to set shipping address')
      console.log(err);
    }));
  }

  selectBillingAddress(){
    return this.addressService.setPaymentAddresses(this.cartService.billingAddress.address_id).pipe(map((res) => {
      console.log('Set billing address!')
      console.log(res);
    }, err => {
      console.log('Failed to set billing address')
      console.log(err);
    }));
  }

【讨论】:

    【解决方案2】:

    如果我理解正确,您需要监听一个 observable(来自 getDefaultAddress()),然后处理另外两个 observable(this.addressService.setShippingAddresses()this.addressService.setPaymentAddresses()),然后调用函数 selectNormalDelivery()

    您可以通过使用 RxJS switchMapcatchErrortap 运算符和 forkJoin() 来实现。试试下面的

    import { forkJoin, EMPTY } from 'rxjs';
    import { tap, catchError, switchMap } from 'rxjs/operators';
    
    ngOnInit() {
      this._addServ.getDefaultAddress().pipe(
        switchMap((res) => {        // <-- map the observable from `getDefaultAddress()` to another observable
          if(res.status) {
            return forkJoin([       // <-- `forkJoin` emits only after the observables complete
              this.selectShippingAddress(), this.selectBillingAddress()
            ])
          }
        })
      ).subscribe(response => {
        this.selectNormalDelivery()
      })
    }
    
    selectShippingAddress() {
      return this.addressService.setShippingAddresses(this.cartService.shippingAddress.address_id).pipe(
        tap((res) => {            // <-- `tap` doesn't alter the response
          console.log('Set shipping address!')
          console.log(res);
        }),
        catchError((err) => {     // <-- `catchError` must return an observable
          console.log('Failed to set shipping address')
          console.log(err);
          return EMPTY;
        }))
    }
    
    
    selectShippingAddress() {
      return this.addressService.setPaymentAddresses(this.cartService.shippingAddress.address_id).pipe(
        tap((res) => {
          console.log('Set billing address!')
          console.log(res);
        }),
        catchError((err) => {
          console.log('Failed to set billing address')
          console.log(err);
          return EMPTY;
        }))
    }
    

    【讨论】:

    • 我喜欢这个!您不仅给了我一个解决方案,还给了我一些概念(Tap、switchMap 等)以供进一步研究。谢谢!
    猜你喜欢
    • 2020-11-15
    • 2022-11-22
    • 2019-05-22
    • 1970-01-01
    • 2021-04-30
    • 2020-07-17
    • 1970-01-01
    • 2020-09-18
    • 1970-01-01
    相关资源
    最近更新 更多