Angular RxJS:Have Observable仅在前一个Observable完成后发出值

Angular RxJS:Have Observable仅在前一个Observable完成后发出值,angular,rxjs,reactive-programming,angular-directive,Angular,Rxjs,Reactive Programming,Angular Directive,我目前正在尝试实现一个Angular structural指令,该指令将读取并存储HTML元素(及其所有子元素)的文本内容,在AfterViewInit上删除其内容,并延迟重新添加内容,每次添加一个字符,使其看起来像是实时键入的 我通过分析目标节点的节点类型来实现这一点。如果是文本,它将把数据内容备份到一个数组中,并继续下一个元素。如果它是不同的节点,它也将递归地分析该节点。这样,我还可以修改包含在目标元素的另一个HTMLElement中的文本 为了将文本写回节点,我使用了observates。

我目前正在尝试实现一个Angular structural指令,该指令将读取并存储HTML元素(及其所有子元素)的文本内容,在AfterViewInit上删除其内容,并延迟重新添加内容,每次添加一个字符,使其看起来像是实时键入的

我通过分析目标节点的节点类型来实现这一点。如果是文本,它将把数据内容备份到一个数组中,并继续下一个元素。如果它是不同的节点,它也将递归地分析该节点。这样,我还可以修改包含在目标元素的另一个HTMLElement中的文本

为了将文本写回节点,我使用了observates。每个节点的原始值一次发出一个字符,每个字符之间的延迟为60毫秒,将其重新添加到原始节点的内容中以模拟键盘输入延迟。在我的anaylze方法中,我还收集了前一个节点内容的长度,将可观测值延迟了这个数字*60ms。我的意图是让下一个可观察的对象仅在前一个对象完成后才发出其值

然而(可能是由于可观测对象的异步性质),通常一个可观测对象会在前一个完全完成之前开始发出值。这使得页面有时看起来好像一次添加了多行,这是我试图避免的行为

这就是我观察到的情况:

from(this.mementos)
  .pipe(
    concatMap(
      memento => of(memento).pipe(delay(memento.previousNodeLength * 60)) // delay Observable by the time it takes to complete the previous node
    )
  )
  .subscribe(memento =>
    from(Array.from(memento.data))
      .pipe(concatMap(text => of(text).pipe(delay(60)))) // delay each character by 60ms
      .subscribe(c => {
        memento.node.data += c;
      })
  );
完成显示问题的工作堆栈闪电战:


如何修改代码,以便一次只添加一个节点的内容

使用
n*60
计算延迟会给出精确的数字,但如果使用
n
setTimeout()
s模拟相同的延迟,则不会匹配,因为
setTimeout()
不能保证精确的超时

因此,您可以删除嵌套的Observable并制作一个链,使用
concatMap
将首先获取每个纪念品,然后获取每个字符

from(this.mementos)
  .pipe(
    concatMap(memento => from(memento.data).pipe( // each memento
      concatMap(char => of({ node: memento.node, char }).pipe(delay(60))), // each char
    ))
  )
  .subscribe(({ node, char }) => {
    node.data += char;
  });
只有在前一个纪念品完成后,才会开始处理下一个纪念品。每个字符在嵌套的可观察对象中延迟


现场演示:

使用
n*60
计算延迟会给出准确的数字,但如果使用
n
setTimeout()
s模拟相同的延迟,则不会匹配,因为
setTimeout()
不能保证准确的超时

因此,您可以删除嵌套的Observable并制作一个链,使用
concatMap
将首先获取每个纪念品,然后获取每个字符

from(this.mementos)
  .pipe(
    concatMap(memento => from(memento.data).pipe( // each memento
      concatMap(char => of({ node: memento.node, char }).pipe(delay(60))), // each char
    ))
  )
  .subscribe(({ node, char }) => {
    node.data += char;
  });
只有在前一个纪念品完成后,才会开始处理下一个纪念品。每个字符在嵌套的可观察对象中延迟

现场演示: