Javascript - 在 Websocket 上使用承诺?

Posted

技术标签:

【中文标题】Javascript - 在 Websocket 上使用承诺?【英文标题】:Javascript - Using Promises on Websocket? 【发布时间】:2017-02-17 18:26:59 【问题描述】:

我在纯 javascript 中使用 Websockets,我想在 Websocket 函数中实现 Promises。我没有收到任何错误,但 Promise 不起作用。

使用下面的代码,我可以成功连接到 socketserver,但 Promise 似乎被跳过了,因为警报的输出总是“失败”。

有人知道这种情况下的问题是什么吗? Ps:我在最新的 Google Chrome 浏览器和最新的 Mozilla Firefox 浏览器中进行了测试,并为这个示例省略了一些基本的检查/错误处理。

function Connect()

    server = new WebSocket('mysite:1234');

    server.onopen = (function()
    
        return new Promise(function(resolve, reject) 
        
            if (true)
            
                resolve();
            
            else
            
                reject();
            
        );
    ).then = (function()
    
        alert('succeeed');
    ).catch = (function()
    
        alert('failed');
    );

【问题讨论】:

是什么让您认为可以成功连接? 仅供参考:您的代码会将server.onopen 设置为最后一个函数(警报失败的那个) - 您可以将.then.catch 更改为任何值,它仍然会做同样的事情.. . 实际上它与var x = ().then = ().catch = (hello:'world') 相同... x 将是hello: 'world' 并且具有.then.catch 属性的中间对象被丢弃 感谢您的解释,肯定有帮助! ***.com/a/49533457/1359764 【参考方案1】:

您尝试在新连接中使用 Promise 似乎有点误导。您将希望从connect() 返回一个承诺,以便您可以使用它来了解服务器何时连接。

看来你可能想要这样的东西:

function connect() 
    return new Promise(function(resolve, reject) 
        var server = new WebSocket('ws://mysite:1234');
        server.onopen = function() 
            resolve(server);
        ;
        server.onerror = function(err) 
            reject(err);
        ;

    );

然后,你会这样使用它:

connect().then(function(server) 
    // server is ready here
).catch(function(err) 
    // error here
);

或者像这样使用async/await

async myMethod() 
  try 
      let server = await connect()
      // ... use server
   catch (error) 
      console.log("ooops ", error)
  

【讨论】:

@Piet - 这根本不是 promise 的工作方式。 Promise 是一次性设备。他们只开火一次。传入的消息可能不止一次出现,因此它们不是承诺的良好设计匹配。另外,您不会在每次发生新事件时都创建新的承诺。这根本不是承诺的工作方式。当您触发一些异步操作并且您正在等待来自该操作的唯一且唯一的响应时,您创建了一个 Promise。然后使用 Promise 来监控那个结果。您只需要使用常规回调来处理重复事件。【参考方案2】:

我遇到了完全相同的问题并创建了很小的websocket-as-promised 库。它返回连接/断开连接和发送消息的承诺:

const WebSocketAsPromised = require('websocket-as-promised');
const wsp = new WebSocketAsPromised();

// connect
wsp.open('ws://echo.websocket.org')
  .then(() => console.log('Connected.')) 
  // send data and expect response message from server
  .then(() => wsp.sendRequest(foo: 'bar'))
  .then(response => console.log('Response message received', response))
  // disconnect
  .then(() => wsp.close())
  .then(() => console.log('Disconnected.'));

关于消息有两种选择:

    如果您发送数据并期望响应消息 - 您可以通过 .sendRequest() 方法使用 promise:

    wsp.sendRequest(foo: 'bar'); // returns promise
    // actually sends message with unique id: id: 'xxxxx', foo: 'bar'
    // promise waits response message with the same id: id: 'xxxxx', response: 'ok'
    

    如果您只是想发送消息而不期望响应 - 使用 .send() 方法:

    wsp.send(data); // returns undefined
    

【讨论】:

服务器如何以客户端期望的方式响应?另一个发送到套接字?退货? 服务器应该响应一条消息,其中包含id 字段。例如,服务器收到请求id: 1, data: 'foo' 并以id: 1, data: 'bar' 响应。【参考方案3】:

扩展@jfriend00 的答案,因为他的答案在每次调用connect 方法时都会尝试创建一个新连接,并且它不考虑连接关闭的情况

function getSocket() 

  if (getSocket.server && getSocket.server.readyState < 2) 
    console.log("reusing the socket connection [state = " + getSocket.server.readyState + "]: " + getSocket.server.url);
    return Promise.resolve(getSocket.server);
  

  return new Promise(function (resolve, reject) 

    getSocket.server = new WebSocket(SOCKET_URL);

    getSocket.server.onopen = function () 
      console.log("socket connection is opened [state = " + getSocket.server.readyState + "]: " + getSocket.server.url);
      resolve(getSocket.server);
    ;

    getSocket.server.onerror = function (err) 
      console.error("socket connection error : ", err);
      reject(err);
    ;
  );

并使用它

getSocket().then(function(server) 
  // do stuff
).catch(function(err) 
    // error here
);

或使用异步/等待

const socket = await getSocket();

【讨论】:

以上是关于Javascript - 在 Websocket 上使用承诺?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Javascript 中为 websocket 的请求标头设置 cookie?

javascript 在 onopen 事件中获取 websocket 错误

从 Python 中的 WebSocket 读取(来自 Javascript WebSocket 的数据)

JavaScript 客户端无法连接到 Spring 4 WebSocket

从 websocket 检索到的触发 javascript

在网络工作者或服务工作者中运行 websocket - javascript