2011-06-06 30 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); 
    } 
}); 
相关问题