Javascript 只有在第二次触发可观察到的源之后,才能重新订阅

Javascript 只有在第二次触发可观察到的源之后,才能重新订阅,javascript,rxjs,Javascript,Rxjs,我正在尝试用一个send事件和一个undo事件组成一个流。发送消息后,会有3s的延迟,您可以撤消消息并将发送的消息返回到文本字段中。如果您开始撰写新邮件,则应在发送的邮件前面加上前缀 到目前为止,我已经成功地创建了延迟发送和撤消功能。问题出现了,当我发送一条消息,撤消它,然后在不接触输入的情况下再次发送它时,我需要更改输入的值以便能够重新发送消息,但无法重新发送恢复的消息 尝试了一些解决方法,如在textarea上调度输入事件,或在restore函数中调用message observable的n

我正在尝试用一个send事件和一个undo事件组成一个流。发送消息后,会有3s的延迟,您可以撤消消息并将发送的消息返回到文本字段中。如果您开始撰写新邮件,则应在发送的邮件前面加上前缀

到目前为止,我已经成功地创建了延迟发送和撤消功能。问题出现了,当我发送一条消息,撤消它,然后在不接触输入的情况下再次发送它时,我需要更改输入的值以便能够重新发送消息,但无法重新发送恢复的消息

尝试了一些解决方法,如在textarea上调度输入事件,或在restore函数中调用message observable的next。他们都没有工作

textarea.addEventListener('input', event => message$.next(event.target.value))
send.addEventListener('click', () => textarea.value = '')

const sendEvent$ = fromEvent(send, 'click')
const undoEvent$ = fromEvent(undo, 'click')
const message$ = new Subject()
let cache = []

sendEvent$
  .pipe(
    withLatestFrom(message$, (_, m) => m),
    tap(m => cache.push(m)),
    delay(3000),
    takeUntil(undoEvent$.pipe(
      tap(restore)
    )),
    repeatWhen(complete => complete)
  )
  .subscribe(x => {
    console.log(x)
    cache = []
  })

function restore() {
  if (!textarea.value) {
    const message = cache.join('\n')
    textarea.value = message
    cache = []
  }
}

链接示例:

订阅者工作正常,只是当触发
撤消事件$
时,您的
消息$
没有得到更新。但是,该值被设置为空字符串

如果撤消,然后键入,然后再次发送,您将看到它在第一时间也可以工作


您需要做的是将
message$
设置为
textarea
的值,然后它就会工作。

订阅者工作正常,只是当
undoEvent$
触发时,您的
message$
不会得到更新。但是,该值被设置为空字符串

如果撤消,然后键入,然后再次发送,您将看到它在第一时间也可以工作


您需要做的是将
消息$
设置为
文本区域的值,然后它就可以工作了。

还原功能中几乎存在问题。恢复时,不会触发“onInput”事件。因此,您的消息队列基本上不会与还原的项目一起排队。@webber给出的建议,您可以在哪里传递消息$。下一条(消息)是非常正确的,这就是您需要做的

但问题是你到底如何设置它。您可以通过restore()中的setTimeout interval设置该值,以便takeUntil()完成,然后将该值放入主题的队列中

function restore() {
  if (!textarea.value) {
    const message = cache.join('\n')
    textarea.value = message
    cache = []
    setTimeout(function(){
      message$.next(message)
    },3000)    
  }
}
(或) 您可以删除

textarea.addEventListener('input', event => message$.next(event.target.value))
并将发送事件处理程序更改为以下内容

send.addEventListener('click', () => {
  message$.next(textarea.value);
  textarea.value =''
})

问题主要存在于恢复功能中。恢复时,不会触发“onInput”事件。因此,您的消息队列基本上不会与还原的项目一起排队。@webber给出的建议,您可以在哪里传递消息$。下一条(消息)是非常正确的,这就是您需要做的

但问题是你到底如何设置它。您可以通过restore()中的setTimeout interval设置该值,以便takeUntil()完成,然后将该值放入主题的队列中

function restore() {
  if (!textarea.value) {
    const message = cache.join('\n')
    textarea.value = message
    cache = []
    setTimeout(function(){
      message$.next(message)
    },3000)    
  }
}
(或) 您可以删除

textarea.addEventListener('input', event => message$.next(event.target.value))
并将发送事件处理程序更改为以下内容

send.addEventListener('click', () => {
  message$.next(textarea.value);
  textarea.value =''
})

嘿,我尝试在restore函数中调用
message$.next(message)
,如果您的意思是这样的,但没有改变行为的话。需要将message设置为cache btw的值。嘿,我已经尝试在restore函数中通过调用
message$.next(message)
来实现这一点,如果您的意思是这样的,但没有改变行为的话。需要将消息设置为cache btw的值。谢谢!我一直认为输入事件需要被触发,你的回答清楚地说明了如何触发。通过这种方式,我可以直接订阅message$、remove withLatestFrom、sendEvent$和textarea侦听器,而不是sendEven$。很酷,谢谢!我一直认为输入事件需要被触发,你的回答清楚地说明了如何触发。通过这种方式,我可以直接订阅message$、remove withLatestFrom、sendEvent$和textarea侦听器,而不是sendEven$。很酷。