带承诺或asynchronouscallback的Socket.io

这可能是一种反模式,但使用socket.io从客户端发送数据到服务器时,模拟promise callback的最佳方法是什么?

对于某些事件,我会非常喜欢它的行为像一个正常的获取请求,所以客户端发送数据到服务器和服务器可以答复一个响应,然后解决或拒绝承诺。

那么,你必须跟踪请求。 因此,我将从一个“全局”计数器开始(它不必是全局的,这对于下面定义的两个函数是可见的就足够了),它将在每个请求中递增(与它一起发送)和“全局”处理器名称空间。 代码可能如下所示:

 var COUNTER = 0, HANDLERS = {}; var custom_get = function(data, clb) { COUNTER++; var msg = {id: COUNTER, data: data}; socket.emit("GET", JSON.stringify(msg)); HANDLERS[COUNTER] = clb; }; socket.on("GET", function(data) { var res = JSON.parse(data); HANDLERS[res.id](res.data); delete HANDLERS[res.id]; }); 

现在你只需要确保服务器将以相同的格式(即JSON)进行响应

 {id:X, data:Y} 

并将相同的请求使用相同的ID。 你可以使用这样的代码:

 custom_get("test", function(res) { console.log(res); }); 

您也可以使用该代码添加例如超时。

最后看看JSON-RPC 。 这是一个简单的协议,你可以很容易地通过WebSocket实现它。

这是我做的。 我创build了一个函数,它发出一个socket命令,然后返回一个promise。 我的一个警告是,我还没有做这个代码很多,所以它可能需要一些调整。 它也要求Q承诺/延期 。

客户端function定义:

 var EmitPromise = function( socket, command, data ) { var deferred = Q.defer(); socket.emit(command, data, function( response ) { if( typeof response === "object" ) { if( response.success === true ) { deferred.resolve(response.data); } else { if( typeof response.message === "string" ) { deferred.reject( response.message ); } else { deferred.reject( "The request was not successful." ) } } } else { deferred.reject( "The response to your request could not be parsed." ); } }); return deferred.promise.timeout( 30000, "The request took too long to respond." ); } 

客户端代码拨打电话:

 EmitPromise( socket, "getValue", "username" ) .then( function( data ) { console.log(data); return EmitPromise( socket, "getValue", "anotherValue" ); }, function( message ) { console.log(message); } ).then( //Chain your commands from here ); 

服务器端处理程序

这个处理程序最重要的部分是第二个参数,这里名为setValueResult,必须用一个包含“success”键的对象来调用,该键包含一个true或false的值。 这是我的一个决定,提供一种方式来拒绝在服务器端出现某种错误时的承诺。

 socket.on( 'getValue', function( valueName, setValueResult ) { var value = getValue(valueName) //Do something with value here if( value ) { setValueResult({ success : success, data : value }); } else { setValueResult({ success : success message : "Unable to retrieve value" }); } }