Angular4如何使用flatMap链接forkJoin

时间:2018-03-15 16:51:02

标签: angular http rxjs chaining

我需要进行5个可以并行执行的http调用+另外需要在这五个调用之后执行的http调用。

我使用forkJoin作为前5个,但我不知道如何链接flatMap(或其他函数)。

forkJoin(
      firstObservable,
      secondObservable,
      thirdObservable,
      ..)
      .subscribe(results => {

        this.myComposedObject = results[0];
        let secondResult = results[1];
        let thirdResult = results[2];
        [...]


        // !!! AT THIS POINT I WOULD NEED TO MAKE AN EXTRA CALL!
        // results[1] contains data I need to make the extra call


        // 
        this.myComposedObject.second = secondResult;
        this.myComposedObject.third = thirdResult;
});

我在组件中执行此操作,因此最后我将数据分配给myComposedObject。

2 个答案:

答案 0 :(得分:3)

就像你说要发出5个并行请求一样,你可以使用forkJoin。然后,您希望在前5个完成后再发出请求,以便将其与concatMap运算符链接起来(或mergeMap也适用于此处)。

然后您需要处理所有结果,这样您就可以使用map将最后一个结果添加到与前五个相同的数组中。

forkJoin(
    firstObservable,
    secondObservable,
    thirdObservable,
    ...
  )
  .concatMap(firstFiveResults => makeAnotherCall(firstFiveResults[1])
    .map(anotherResult => [...firstFiveResults, anotherResult])
  )
  .subscribe(allResults => {
    this.myComposedObject.second = allResults[1];
    this.myComposedObject.third = allResults[2];
    // allResults[5] - response from `makeAnotherCall`
    ....
  });

答案 1 :(得分:0)

谢谢,这指向了正确的方向。 我在结果类型方面遇到了一些问题。当我试图分配

weak

编译器抱怨类型转换,所以我会在这里为其他人报告我的解决方案。

为了摆脱这个问题,你可以利用“解构”(这里有更多信息:https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

@IBOutlet weak fileprivate var yourLabel: UILabel!

var timeMin = 0
var timeSec = 0
weak var timer: Timer?

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // if your presenting this vc yourLabel.txt will show 00:00
    yourLabel.txt = String(format: "%02d:%02d", timeMin, timeSec)
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)

    resetTimerToZero()
}

// MARK:- recordButton
@IBAction fileprivate func recordButtonTapped(_ sender: UIButton) {

    startTimer()

    movieFileOutput.startRecording(to: videoUrl, recordingDelegate: self)
}

// MARK:- Timer Functions
fileprivate func startTimer(){

    // if you want the timer to reset to 0 every time the user presses record you can uncomment out either of these 2 lines

    // timeSec = 0
    // timeMin = 0

    // If you don't use the 2 lines above then the timer will continue from whatever time it was stopped at
    let timeNow = String(format: "%02d:%02d", timeMin, timeSec)
    yourLabel.txt = timeNow

    stopTimer() // stop it at it's current time before starting it again
    timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
                self?.timerTick()
            }
}

@objc fileprivate func timerTick(){
     timeSec += 1

     if timeSec == 60{
         timeSec = 0
         timeMin += 1
     }

     let timeNow = String(format: "%02d:%02d", timeMin, timeSec)

     yourLabel.txt = timeNow
}

// resets both vars back to 0 and when the timer starts again it will start at 0
@objc fileprivate func resetTimerToZero(){
     timeSec = 0
     timeMin = 0
     stopTimer()
}

// if you need to reset the timer to 0 and yourLabel.txt back to 00:00
@objc fileprivate resetTimerAndLabel(){

     resetTimerToZero()
     yourLabel.txt = String(format: "%02d:%02d", timeMin, timeSec)
}

// stops the timer at it's current time
@objc fileprivate stopTimer(){

     timer?.invalidate()
}