2011-06-06 50 views
1

我的應用程序中有這部分代碼。爲什麼async在循環中的node.js中發生錯誤

card.getcard(command, function(toproceed,resultscard) { 
    console.log('entry other cards api result'+sys.inspect(resultscard)); 
    if (resultscard.length==0) { 
     return proceed(false,{errno:'011','queueno' : request.queueno, message:'there is no access card for particular gib'}); 
    } 

    for (var i=0; i<resultscard.length;i++) { 
     console.log('card owner'+resultscard[i].owner); 

     //checking that any users is in inside of gib 
     server.wrap(function(){ 
     server.getchannel("channels."+request.gibid+'-I', function(err, channel) { 
      if (channel.users) { 
      var arr=channel.users.split(','); 
      if (functions.in_array(resultscard[i].owner, arr)) { 
       response.users.push(resultscard[i].owner); 
      } 
      } 
     }); 
     if(i==resultscard.length-1) { 
      if (response.users.length<=0) { 
      //here need to send sorry event that no owner is online 
      request._command='sorry'; 
      } else { 
      request._command='knock'; 
      } 
      return proceed(true,response); 
     } 
     }); 

    } 
    }); 

當執行這給我錯誤。

entry other cards api result[ { cardid: 16, 
    cardtype: 'A', 
    status: 'A', 
    refername: 'rahulgib', 
    refertype: 'G', 
    owner: 'rahul' }, 
    { cardid: 27, 
    cardtype: 'A', 
    status: 'A', 
    refername: 'rahulgib', 
    refertype: 'G', 
    owner: 'namita' } ] 
card ownerrahul 
card ownernamita 

node.js:178 
     throw e; // process.nextTick error, or 'error' event on first tick 
     ^
TypeError: Cannot read property 'owner' of undefined 
    at Object.callback (/home/myhome directory /redisyoungib/lib/yapi.js:271:50) 
    at RedisClient.return_reply (/usr/local/lib/node/.npm/redis/0.6.0/package/index.js:384:29) 
    at HiredisReplyParser.<anonymous> (/usr/local/lib/node/.npm/redis/0.6.0/package/index.js:78:14) 
    at HiredisReplyParser.emit (events.js:64:17) 
    at HiredisReplyParser.execute (/usr/local/lib/node/.npm/redis/0.6.0/package/lib/parser/hiredis.js:35:22) 
    at RedisClient.on_data (/usr/local/lib/node/.npm/redis/0.6.0/package/index.js:325:27) 
    at Socket.<anonymous> (/usr/local/lib/node/.npm/redis/0.6.0/package/index.js:90:14) 
    at Socket.emit (events.js:64:17) 
    at Socket._onReadable (net.js:673:14) 
    at IOWatcher.onReadable [as callback] (net.js:177:10) 

我不明白爲什麼會出現此錯誤?

獲取卡片給出從卡片的結果

包裝功能執行回調函數。

getchannel從redis中返回數據。

回答

3

您創建和傳遞到server.getchannel的函數是關閉i變量(好吧,覆蓋範圍內的所有內容,但我們關心的是i)。他們得到一個持久參考i,而不是複製它的價值,當它的功能被創建。這意味着當函數運行時,它將使用當前的值,而不是創建函數時的值。結果是所有這些函數將使用相同的值i,這是循環結束時的值。由於超出了數組的末尾,因此resultscard[i]undefined,因此嘗試從中讀取owner屬性失敗。 (更多關於關閉:Closures are not complicated

所以,你想要做的就是讓這些功能時可以關上的東西,是的i價值的副本。通常的做法是有一個工廠函數來創建它們並接受用作參數的值。工廠函數創建回調函數,該函數關閉參數,其值不會更改。

沒有通過它讀得仔細,將其應用於你的代碼可能看起來東西這樣的:

card.getcard(command, function(toproceed,resultscard) { 
    console.log('entry other cards api result'+sys.inspect(resultscard)); 
    if (resultscard.length==0) { 
     return proceed(false,{errno:'011','queueno' : request.queueno, message:'there is no access card for particular gib'}); 
    } 

    for (var i=0; i<resultscard.length;i++) { 
     console.log('card owner'+resultscard[i].owner); 

     //checking that any users is in inside of gib 
     server.wrap(function(){ 
     server.getchannel("channels."+request.gibid+'-I', makeCallback(i)); 
     // Call the factory function, passing in `i` -----^ 
     if(i==resultscard.length-1) { 
      if (response.users.length<=0) { 
      //here need to send sorry event that no owner is online 
      request._command='sorry'; 
      } else { 
      request._command='knock'; 
      } 
      return proceed(true,response); 
     } 
     }); 

    } 

    // The factory function  
    function makeCallback(index) { 
     return function(err, channel) { 
     if (channel.users) { 
      var arr=channel.users.split(','); 
      // Note we use `index` -- our argument -- not `i` below 
      if (functions.in_array(resultscard[index].owner, arr)) { 
      response.users.push(resultscard[index].owner); 
      } 
     } 
     }; 
    } 
    }); 

現在我們在makeCallback創建回調關閉在index論據創建它的電話,這沒什麼其他變化。我們通過i,我們在那裏。它仍然是一個關於其他事情的關閉(因爲定義了makeCallback),但它使用index,因此它處理正確的條目。

+0

@TJ我應該怎麼做才能刪除錯誤?並正確執行我的程序 – XMen 2011-06-06 09:14:52

+0

@Rahul:我已經添加了一些說明和常見方法的代碼。 – 2011-06-06 09:17:06

+0

@TJ我已更新我的代碼acc。回答,並測試它,給我錯誤,'resultscard沒有定義',我應該怎麼做這個 – XMen 2011-06-06 09:31:49

1

這是javascript scope imo中最棘手的部分之一。

當你是一個循環內,並且您是根據從一個循環索引創建匿名函數,你需要做的是這樣綁定討好,或匿名自我執行功能確保你正在捕捉正確的價值。

var set = []; 

// Store a list of functions in an array 
for (var i = 0; i<5; i++) { 
    set.push(function(){ 
     console.log(i); 
    }); 
} 

// Pull the functions back out and execute them 
for (var x = 0; x<5; x++) { 
    set[x](); 
} 

的這個輸出:

5 
5 
5 
5 
5 

預期

概念是由本實施例中示出的?不會,你會期望0,1,2,3,4

這是因爲基於外部範圍的索引的變量(在你創建的函數之外)不會被複制,它會在函數被執行(一段時間後,循環已經完成)。

爲了獲得理想的效果,您可以執行上面提到的任何事情。這(這可以說是最簡單的)是自執行的匿名函數

var set = []; 

// Store a list of functions in an array 
for (var i = 0; i<5; i++) { 
    (function(i){ 
     set.push(function(){ 
     console.log(i); 
     }); 
    })(i); 
} 

// Pull the functions back out and execute them 
for (var x = 0; x<5; x++) { 
    set[x](); 
} 

這給你的0所需的輸出,1,2,3,4,因爲我們已經通過創建成立了一個新的作用域一個新函數,傳遞給我們感興趣的變量(i),並立即用所需的參數執行該函數。它採用(函數(a){})(a)的基本形式。

不知道你的代碼的細節超出了這個塊,你可以做這樣的事情:

card.getcard(command, function(toproceed,resultscard) { 
    console.log('entry other cards api result'+sys.inspect(resultscard)); 
    if (resultscard.length==0) { 
     return proceed(false,{errno:'011','queueno' : request.queueno, message:'there is no access card for particular gib'}); 
    } 

    for (var i=0; i<resultscard.length;i++) { 
     (function(resultscard, i){ 
      console.log('card owner'+resultscard[i].owner); 

      //checking that any users is in inside of gib 
      server.wrap(function(){ 
      server.getchannel("channels."+request.gibid+'-I', function(err, channel) { 
       if (channel.users) { 
       var arr=channel.users.split(','); 
       if (functions.in_array(resultscard[i].owner, arr)) { 
        response.users.push(resultscard[i].owner); 
       } 
       } 
      }); 
      if(i==resultscard.length-1) { 
       if (response.users.length<=0) { 
       //here need to send sorry event that no owner is online 
       request._command='sorry'; 
       } else { 
       request._command='knock'; 
       } 
       return proceed(true,response); 
      } 
      }); 
     })(resultscard, i); 
    } 
}); 
相關問題