2014-04-13 86 views
0

我收到'回調已用'錯誤,我不知道爲什麼。我正在使用異步並希望鏈接兩個函數,因爲第二個函數依賴於要完成的第一個函數。異步 - 已使用回調錯誤

我是Node.js的新手,仍然圍繞着異步/回調。非常感謝您的幫助。

getCdn接受cnames,如果cname是CDN的一部分,它會將結果推送到名爲cdnAttrs的全局變量中。

function getCdn(cnameDict, callback) { 
    // cdnAttributes contains associative array with each web attribute: {name_in_db : code_snippet_to_find_in_cname} 
    for (var key in cdnAttributes) { 
    if (cdnAttributes.hasOwnProperty(key)) { 
     var snippet = -1; 
     // some technologies contain multiple code snippets, in that case they are stored as array. Single code snippets are stored as string 
     if (!Array.isArray(cdnAttributes[key])) { 
     snippet = cnameDict['cname'].indexOf(cdnAttributes[key]) 
     } 
     else { 
     // check each code snippet within the array, if any match the source code, update 'snippet' 
     for (var n = 0; n < cdnAttributes[key].length; n++) { 
      var val = cnameDict['cname'].indexOf(cdnAttributes[key][n]) 
      if (val > -1) { 
      snippet = val 
      } 
     } 
     } 
     // if attribute found in tag, create cdnAttrs[cdn] = [{from: hostname, proof: cname}, {from: hostname2, proof: cname2}, ...] 
     if (snippet > -1) { 
     try { 
      cdnAttrs[key].push(cnameDict); 
     } 
     catch (e) { 
      cdnAttrs[key] = []; 
      cdnAttrs[key].push(cnameDict); 
     } 
     callback(); 
     } else { 
     callback(); 
     } 
    } else { 
     callback(); 
    } 
    } 
} 

我的異步函數如下所示:

async.series([ 
    // THIS FUNCTION WORKS FINE... 
    function(callback) { 
    async.each(toCheck, function(hostname, callback) { 
     getCname(hostname, callback); 
    },callback); 
    }, 
    // THIS FUNCTION RETURNS RETURNS Error("Callback was already called.") 
    function(callback) { 
    async.each(toCheckCnames, function(cnameDict, callback) { 
     getCdn(cnameDict, callback); 
    },callback); 
    } 
], function(err){ 
    if(err) { 
    console.log('ERROR'); 
    }else{ 
    console.log('toCheckCnames is done: '+JSON.stringify(toCheckCnames)); 
    console.log('cdnAttrs is done: '+JSON.stringify(cdnAttrs)); 
    } 
}) 

的getCnames功能的工作原理:

function getCname(hostname, callback){ 
    dns.resolve(hostname, 'CNAME', function(error, cname) { 
    if (cname) { 
     toCheckCnames.push({from: hostname, cname: cname[0]}); 
     callback(); 
     } 
    // if not CNAMEd, check SOA on www.domain.com and domain.com 
    else { 
     if (hostname.slice(0,4) == 'www.') { 
     hostname = hostname.slice(4); 
     } 
     nativedns.resolve(hostname, 'SOA', function(error, records) { 
     if(!error && records) { 
      toCheckCnames.push({from: hostname, cname: records[0]['primary']}); 
      callback(); 
     } 
     else if (!error) { 
      hostname = 'www.'+ hostname 
      nativedns.resolve(hostname, 'SOA', function(error, records) { 
      if (!error) { 
       toCheckCnames.push({from: hostname, cname: records[0]['primary']}); 
       callback(); 
      } 
      else callback() 
      }); 
     } 
     else callback() 
     }); 
    } 
    }); 
} 

回答

1

getCdn功能是廁所p將在每次迭代後調用回調函數。如果調用回調旨在停止循環執行,則可以執行return callback()。否則,您需要重新組織代碼,以在函數完成時僅調用一次回調。

UPDATE:

您也可以簡化您的通話async.each:

// Was this 
async.each(toCheck, function(hostname, callback) { 
    getCname(hostname, callback); 
},callback); 

// Could be this 
async.each(toCheck, getCname, callback); 
+0

我還添加了getCname功能作爲參考。根據我的理解,getCname會對async.each進行回調。只有在遍歷整個數組的async.each之後,它纔會執行最後的回調,這會使async.series移動到下一個函數。 getCname和getCdn有什麼不同,getCname可以正常工作,並且getCdn會引發回調?應該getCdn爲每次迭代回調async.each?我的斷開連接在哪裏? –

+0

在任何使用函數的異步方法中,回調基本上用於說「此函數已完成處理」。如果您來自阻塞語言,請將回調視爲返回聲明。由於節點的非阻塞性質,這是必需的。 'getCdn'函數爲每個循環調用回調函數,這是錯誤的,因爲函數實際上並未完成處理。相反,'getCname'函數只會在回調完成後調用回調函數。 –

+0

爲了適應回調,您可以更改剛剛讀取'callback()'以讀取'return callback()'的行。這會讓你知道它應該做什麼。如果你的代碼仍然有效,那麼你正確地使用回調了! –