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