2011-06-06 2 views
1

J'ai cette partie du code dans mon application.pourquoi async dans node.js dans la boucle donnant l'erreur

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); 
     } 
     }); 

    } 
    }); 

lors de l'exécution de cette erreur.

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) 

Je ne comprends pas pourquoi il donne cette erreur?

carte get donne le résultat de mysql de la carte

fonction wrap exécuté la fonction de rappel. Getchannel renvoie les données de Redis.

Répondre

3

Les fonctions que vous créez et passez dans server.getchannel sont des fermetures sur la variable i (bien, sur tout ce qui est dans la portée, mais c'est i nous sommes concernés). Ils obtiennent une référence durable à i, pas une copie de sa valeur à partir de quand la fonction a été créée. Cela signifie que lorsque la fonction s'exécute, elle utilise la valeur actuelle de i, et non la valeur telle qu'elle était lors de la création de la fonction. Le résultat est que tous de ces fonctions utilisera la même valeur de i, qui est la valeur à la fin de la boucle. Puisque c'est au-delà de la fin du tableau, resultscard[i] est undefined et donc essayer de lire une propriété owner échoue. (Plus sur les fermetures: Closures are not complicated)

donc ce que vous voulez faire est d'obtenir ces fonctions de fermer sur quelque chose qui est une copie de la valeur de i. La façon habituelle de le faire est d'avoir une fonction d'usine qui les crée et qui accepte la valeur à utiliser comme argument. La fonction factory crée la fonction callback, qui se ferme sur l'argument, dont la valeur ne change pas.

Sans la lecture par trop attentivement, l'application que votre code ressemble probablement quelque chose comme ceci:

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); 
      } 
     } 
     }; 
    } 
    }); 

Maintenant, le rappel que nous créons dans makeCallback ferme sur l'argument index pour l'appel qui l'a créé, que rien d'autre ne change. Nous passons i dans, et nous y sommes. C'est toujours une fermeture sur les autres choses (à cause de où makeCallback est défini), mais il utilise index avec eux afin qu'il gère la bonne entrée.

+0

@TJ Que dois-je faire pour supprimer l'erreur? et exécuter mon programme correctement – XMen

+0

@Rahul: J'ai ajouté quelques notes et code illustrant l'approche habituelle. –

+0

@TJ j'ai mis à jour mon code acc. pour répondre, et le tester, il me donne l'erreur que 'resultscard n'est pas défini', que dois-je faire pour cela – XMen

1

Ceci est l'une des parties les plus difficiles de javascript scope imo.

Lorsque vous êtes dans une boucle et vous créez des fonctions anonymes en fonction de l'index d'une boucle, vous devez faire quelque chose comme bind, taitement ou auto anonyme exécuter des fonctions pour vous assurer vous capturez la bonne valeur.

Le concept est illustré par cet exemple:

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](); 
} 

La sortie de c'est:

5 
5 
5 
5 
5 

ATTENDUS? En effet, 0, 1, 2, 3, 4

Cela est dû au fait que les variables basées sur l'index de la portée externe (en dehors de la fonction que vous avez créée) ne sont pas copiées, elles sont évaluées lorsque la fonction est exécuté (un peu plus tard, après que la boucle soit déjà passée).

Pour obtenir l'effet désiré, vous pouvez faire l'une des choses que j'ai mentionnées ci-dessus. Ce (ce qui est sans doute le plus simple) est une auto exécution fonction anonyme:

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](); 
} 

Cela vous donne la sortie désirée de 0, 1, 2, 3, 4 parce que nous avons établi un nouveau champ en créant une nouvelle fonction, passée dans la variable qui nous intéresse (i), et a exécuté la fonction immédiatement avec les paramètres désirés. Il prend la forme de base de (function (a) {}) (a).

Sans connaître les détails de votre code au-delà de ce bloc, vous pourriez faire quelque chose comme ceci:

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); 
    } 
}); 
Questions connexes