如何在连接之前*干净地“关闭”/“中止”WebSocket 连接

问题描述 投票:0回答:1

我正在建立一个 ws 连接,但在某些情况下,我需要/想要干净地中止请求,而控制台不会记录这样的错误 -

WebSocket 连接到 'ws://xyz:3001/?失败:WebSocket 已关闭 在建立连接之前。

代码如下:

const ws = new WebSocket(`${url}`);

setTimeout(() => ws.close(), random); // some other event that occur at any given time "random"

一个简单的用例是,当用户打开视图时启动连接,但随后快速关闭视图,这可能/应该中止连接请求。

有没有办法彻底中止连接请求,这样我就不会在浏览器控制台中收到太多类似的日志?

javascript websocket browser browser-console abortcontroller
1个回答
1
投票

您可以测试一下

readyState
属性是否有帮助。

您可以在尝试关闭连接之前使用它来检查连接的当前状态。这将允许您避免在连接未处于打开状态时尝试关闭连接,从而防止错误消息出现在控制台中。

WebSocket API 通过

readyState
属性提供不同的状态:

  • CONNECTING
    (0): 连接尚未打开。
  • OPEN
    (1):连接已打开并准备好进行通信。
  • CLOSING
    (2): 连接正在关闭中。
  • CLOSED
    (3): 连接已关闭或无法打开。

您可以使用这些状态来决定何时适合关闭 WebSocket:

const ws = new WebSocket(`${url}`);

setTimeout(() => {
    // Check if the WebSocket's state is CONNECTING or OPEN before attempting to close it
    if (ws.readyState === WebSocket.CONNECTING || ws.readyState === WebSocket.OPEN) {
        ws.close();
    }
}, random); // some other event that occur at any given time "random"

该代码修改确保仅当 WebSocket 仍在连接或已打开时才调用

ws.close()
。如果 WebSocket 正在关闭或已经关闭,再次调用
close()
可能会导致不必要的错误或日志。

我 99% 确信调用

ws.close() when ws.readyState === WebSocket.CONNECTING
会在控制台中记录错误,我只想有效地删除本地侦听器并放入 void

考虑到 WebSocket API 在直接处理此特定用例方面的局限性,您可以考虑使用标志来防止提前关闭的操作。

let proceedWithConnection = true;

const ws = new WebSocket(`${url}`);

// Set up WebSocket event listeners
ws.onopen = () => {
    if (!proceedWithConnection) {
        ws.close(); // Close immediately if we have decided not to proceed
    } else {
        // Proceed with setting up the connection
    }
};

// Some other event that might occur at any given time
setTimeout(() => {
    proceedWithConnection = false;
}, random);

或者您可以延迟实际的连接尝试,直到您更确定需要它。这可能涉及设置初步延迟(如前所述,消除连接尝试的抖动),以确保用户的操作需要 WebSocket 连接:

let shouldConnect = true;

setTimeout(() => {
    if (shouldConnect) {
        const ws = new WebSocket(`${url}`);
        // Set up your WebSocket connection here
    }
}, delayBeforeConnecting);

// Some event indicates the connection should not proceed
setTimeout(() => {
    shouldConnect = false;
}, random);

这也与OP的

whatwg/websockets
第57期相关,其中来自Chromium项目的Adam Rice (
ricea
)
补充道:

WebSocket

close()
方法已经可以用来执行此操作。如果您不喜欢 Chrome 在发生这种情况时打印控制台消息的行为,您应该在 https://crbug.com/.

提交问题

提议的 WebSocketStream API 使用

AbortController
来取消握手。

我们不太可能将其添加到 WebSocket API 中,因为它可以使用类似的函数轻松模拟

function AbortableWebSocket(url, signal) {
  signal.throwIfAborted();
  const ws = new WebSocket(url);
  const abortHandler = () => ws.close();
  signal.addEventListener('abort', abortHandler);
  ws.addEventListener('close', 
    () => signal.removeEventListener('abort', abortHandler));
  return ws;
}

因此

signal.throwIfAborted()
调用将确保,如果在启动 WebSocket 连接之前操作已中止,它将立即抛出异常,从而阻止连接。
如果在连接尝试开始后但在完全打开之前发出中止事件信号,则会调用
ws.close()
来终止尝试。连接成功打开后,它将删除中止事件侦听器以清理资源。

您可以向该函数添加所有 WebSocket 事件侦听器的错误处理和清理,以确保没有泄漏:

function AbortableWebSocket(url, signal) {
    signal.throwIfAborted();
    const ws = new WebSocket(url);
    const abortHandler = () => ws.close();
    signal.addEventListener('abort', abortHandler);

    // Cleanup function to remove all listeners
    const cleanup = () => {
        signal.removeEventListener('abort', abortHandler);
        ws.removeEventListener('open', onOpen);
        ws.removeEventListener('error', onError);
        ws.removeEventListener('close', onClose);
    };

    const onOpen = () => cleanup();
    const onError = () => cleanup();
    const onClose = () => cleanup();

    ws.addEventListener('open', onOpen);
    ws.addEventListener('error', onError);
    ws.addEventListener('close', onClose);

    return ws;
}
© www.soinside.com 2019 - 2024. All rights reserved.