2

我正在用socket api写一个 Chrome 扩展(虽然这个文档已经过时了,最新版本的 api 在这里),我发现代码真的很难组织:

所有方法都在 namespace 下,为了简单起见chrome.experimental.socket,我将在socket下面使用。

socket.create("tcp", {}, function(socketInfo){
    var socketId = socketInfo.socketId;

    socket.connect(socketId, IP, PORT, function(result){
        if(!result) throw "Connect Error";        

        socket.write(socketId, data, function(writeInfo){
            if(writeInfo.bytesWritten < 0) throw "Send Data Error";

            socket.read(socketId, function(readInfo){
                if(readInfo.resultCode < 0) throw "Read Error";
                var data = readInfo.data; // play with the data
                // then send the next request
                socket.write(socketId, data, function(writeInfo){
                    socket.read(socketId, function(readInfo){
                        // ............
                    });
                });
            });
        })
    });
})

因为socket.writesocket.read都是异步的,所以我必须嵌套回调以确保在上一个请求得到正确响应之后发送下一个请求。

管理这些嵌套函数真的很难,我该如何改进呢?

更新

我想要一个send可以用作的方法:

send(socketId, data, function(response){
    // play with response
});
// block here until the previous send get the response
send(socketId, data, function(response){
    // play with response
});
4

2 回答 2

1

(类似的)这个怎么样?

var MySocket = {
  obj: null,
  data: null,
  start: function() { ... some code initializing obj data, ending with this.create() call },
  create: function() { ... some code initializing obj data, ending with this.connect() call },
  connect: function() { ... some connection code, ending with this.write() call },
  write: function() { ... some writing code that updates this.data, ending with this.read() call },
  read: function() { ... you probably get the idea at this point )) ... },
};

这个对象可以MySocket.start()和什么一起使用。这个想法是将所有数据(和嵌套调用)封装在单个(但更多或更少全局可用)对象中。

甚至更多,可以创建两个对象:一个纯粹用于写入目的,另一个用于纯粹阅读目的,每个对象都有自己的操作data,然后将它们(以及它们之间的调用,可以这么说)包装到单个 SocketManager 对象中。

于 2012-05-21T14:27:27.330 回答
0

考虑使用异步延续传递风格,其中函数以 SetInterval 调用结束,调用它们所传递的函数。然后我们构造一个函数,将两个函数缠绕在一起,使用这种机制相互调用。它的胆量是这样的:

var handle;
// pairs two functions
function pair(firstfunc, secondfunc, startarg) {
  var callbackToFirst = function(valuetofill) {
    handle = setInterval(firstfunc(valuetofill,callbackToSecond));
  };
  var callbackToSecond = function(valuetofill) {
    handle = setInterval(secondfunc(valuetofill,callbackToFirst));
  };

  callbackToFirst(startarg);
}

我们在这里所做的是构造一对相互调用的回调,它们接受一个参数,每个参数都包含对两个相互调用函数的引用。然后我们通过调用第一个回调来启动该过程。

为示例读取和写入函数对构造该对(假设您已在封闭对象定义中设置了 socketId):

// starts read/write pair, sets internal variable 'handle' to 
//   interval handle for control
function startReadWrite(initialarg, myDataFunc) {
    var readcall = function(value, func) {
        readSocket(getData(myDataFunc(func)));
    };
    var writecall = function(value, func) {
        writeSocket(checkBytesWritten(func));
    };
    handle = pair(readcall, writecall, initialarg);
}

对象的其余部分是这样的:

function myIO() {
    var socketInfo, socketId, handle;

    function create(func) {
        socket.create('tcp',{},function(thisSocketInfo) {
            socketInfo = thisSocketInfo;
        }
        setInterval(func(this),0);
    }

    function connect(IP, PORT, func) {
        socket.connect(p_socketId, IP, PORT, function() {
            if(!result) throw "Connect Error";
                setInterval(func(result),0);
            });
    }

    function readSocket(func) {
        socket.read(p_socketId, function(readInfo){ 
            setInterval(func(readInfo),0);
        });
    }

    function writeSocket(data, func) {
        socket.write(p_socketId, data, function(writeInfo){
            setInterval(func(writeInfo),0)
        });
    }

    function checkBytesWritten(writeInfo, func) {
        if(writeInfo.bytesWritten < 0) throw "Send Data Error";
        setInterval(func(writeInfo),0);
    }

    function getData(readInfo, func) {
        if(readInfo.resultCode < 0) throw "Read Error";
        var data = readInfo.data;
        setInterval(func(data),0);
    }


    //** pair and startReadWrite go here **//

}

最后调用设置整个事情:

var myIOobj = new myIO();
myIOobj.create(startReadWrite(myDataFunc));

笔记:

  1. 这是为了展示一种风格,而不是准备好的代码!不要只是复制和粘贴它。
  2. 不,我没有测试过这个;我做 javascript 但还没有 Chrome API 的东西。我专注于回调机制等。
  3. 小心不同类的回调;单参数回调(如读取和写入回调),采用单个值(可能由 API 定义),以及 2 个参数回调(如大多数方法),最后采用一个参数和一个要调用的函数。
  4. getData 方法接受一个回调并传递data给它;此回调 (myDataFunc) 是实际使用数据的函数。它需要将回调作为第二个参数并同步或异步调用它。

TLDR:考虑使用异步调用来避免嵌套。我已经给出了一个机制的模糊示例,让两个函数在需要时使用这种风格连续调用对方。

Although I call it asynchonous, the setInterval calls will execute serially, but the key is that the stack is cleared after the parent call is done, rather than adding endless layers with nesting.

于 2012-05-21T16:24:55.237 回答