JS SSE 回调不适用于 EventListener

JS SSE callback isn't working with EventListener

我正在使用 JS 库在我的 html 页面上流式传输服务器发送的事件:

    <html>
    <textarea rows='14' id="value" placeholder="anything you want here"></textarea>
    <button type="button" onclick="post(clip)">get</button>
    
    </html>
    <script type="text/javascript" src="sse.js"></script>
    <script>

url = "http://ac6ba97b046a5dcc677e.elb.us-east-1.amazonaws.com/myapi";
let textArea = document.getElementById("value");

function clip(){
  s = textArea.value;
  s = s.slice(0, -5);
  textArea.value = s;
  console.log('hello');
}

function post(callback){
    var v = String(textArea.value);
    console.log(v);
    var source = new SSE(url, {
      method: 'POST',
      headers: { 'Content-Type': 'text/plain' },
      payload: v
    });
    var arr = [];
    source.addEventListener('message', function (e) {
      arr.push(e.data);
      textArea.value = arr.map(el => el || " ").join('');
    });
    source.stream();
    callback();
}

</script>

单击该按钮时,将使用 POST 方法将数据发送到服务器,并使用从服务器接收的数据填充文本框。我想在执行 post() 函数后用 clip() 剪辑文本框中的文本。执行过程必须是这样的:

1. post() logs textArea value
2. source.stream() is executed, textbox populated
3. clip() clips last 5 characters and logs 'hello'

但我却得到了这个:

1. post() logs textArea value
2. clip() clips last 5 characters and logs 'hello'
3. source.stream() is executed, textbox populated

由于某种原因 clip()source.stream() 之前执行,即使在添加回调之后也是如此。

我正在使用的 sse.js 文件。

[编辑] 将 callback() 移动到 'message' 处理程序的末尾后,问题仍然存在:

function post(callback){
    var v = String(textArea.value);
    console.log(v);
    var source = new SSE(url, {
      method: 'POST',
      headers: { 'Content-Type': 'text/plain' },
      payload: v
    });
    var arr = [];
    source.addEventListener('message', function (e) {
      arr.push(e.data);
      textArea.value = arr.map(el => el || " ").join('');
      callback();
    });
    source.stream();
}

有人知道是什么原因造成的吗?

当您的脚本调用 source.stream(); 时,它正在执行一个 XMLHttpRequest.send() 操作,默认情况下是异步的。

所以,发生了什么:

  1. 用户点击,post()被调用
  2. SSE 对象及其事件侦听器已设置
  3. source.stream() 被调用,它向服务器发送请求。
  4. callback()(即clip())被称为
  5. 服务器发回响应
  6. 您的 message 事件处理程序被调用
  7. textArea.value 设置

幸运的是,解决方法很简单:您只希望在收到消息时调用 callback()。因此,将 callback() 移动到 message 事件处理程序的末尾,而不是 post().

的末尾

它会在收到每个消息事件后执行此操作。如果您只希望它在第一个事件之后发生,您将需要实施一些逻辑来跟踪已收到的事件数量。 (如果只有一个消息事件,您应该使用 Ajax 调用,而不是 SSE/EventSource 调用。)

更新:评论中的讨论开始超出您原来问题的范围(答案是,简单地说,“它是异步的,不是同步的”) .但我认为这里值得指出的是,每次用户单击按钮时,您都会设置一个新的 SSE 对象。每个 SSE 对象都有自己专用的 TCP/IP 套接字和自己的侦听器函数。 这(通常)不是一个好主意:而是在您的网络应用程序启动时创建一次 SSE 连接。

而且,尽管您的 SSE polyfill 库允许使用 POST,但 。如果您只希望应用程序在用户按下按钮时轮询服务器,请考虑从使用 SSE 切换到正常 AJAX.