2

我正在写一个Chrome扩展与socket api(虽然这个文档是过时的,API的最新版本是here),我发现该代码是真的很难组织:我该如何优化嵌套函数太多的代码?

所有方法在名称空间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是异步的,我不得不窝回调,以确保下一个请求被发送后,先前的请求得到了正确的响应。

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

UPDATE

我想有一个方法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 
}); 
+0

http://stackoverflow.com/questions/8302218/chrome-tabs-create-function-wrapper-why-doesn-this-work –

+1

@ GRIGORE-TURBODISEL你可能认真吗? – wong2

+0

Yea man,com'on。这就是我从'//在这里阻塞直到上一次发送得到响应'所得到的结果。 –

回答

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:考虑使用异步调用来避免嵌套。我已经给出了一个机制的模糊例子,它让两个函数不断使用这种风格互相调用,这似乎是需要的。

虽然我称它为异步,但setInterval调用将按顺序执行,但关键是在父调用完成后清除堆栈,而不是使用嵌套添加无限层。

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对象。