2013-11-19 3 views
1

Я пытаюсь разгадать этот неблокирующий бизнес.node.js callback внутри цикла результата mysql

Можете ли вы сказать мне, что я делаю неправильно здесь? Я попытался добавить функцию retrieveContactName, которая получает дополнительную информацию от db перед записью в сокет. Я попытался сделать обратный вызов, но я получил ошибку внизу.

case 'getConversations': 
    var sip = parts[1]; 
    var pass = parts[2].replace(/[\n\r]/g, ''); //strip that carriage return 
    var sql = "SELECT DISTINCT(session) FROM im WHERE sip = "+connection.escape(sip)+" AND password = "+connection.escape(pass)+" ORDER BY timestamp DESC"; 
    connection.query(sql, function(err, results) { 
     if (err) winston.warn(err); 
     for (var i=0; i < results.length; i++) { 
      retrieveContactName(results[i].session, sip, pass, function(value) { 
       sock.write('Conversations '+results[i].session+' '+value+'\n'); 
      }); 
     } 
    }); 
break; 

других

function retrieveContactName(session, user, pass, callback) { 
    var sql = "SELECT `im_from` FROM `im` WHERE `session` = "+connection.escape(session)+" AND `im_to` != "+connection.escape(session)+" AND `sip` = "+connection.escape(user)+" AND `password` = "+connection.escape(pass)+" LIMIT 1"; 
    connection.query(sql, function(err, results) { 
     if (err) winston.warn(err); 
     if (results.length > 0) { 
      callback(results[0].im_from); 
     } else { 
      callback(session.replace("contact:","")); 
     } 
    }); 
} 

и моя ошибка

TypeError: Cannot read property 'session' of undefined 
    at /home/ubuntu/socket/server.js:44:47 
    at Query._callback (/home/ubuntu/socket/server.js:79:4) 
    at Query.end (/home/ubuntu/socket/node_modules/mysql/lib/protocol/sequences/Sequence.js:75:24) 
    at Query._handleFinalResultPacket (/home/ubuntu/socket/node_modules/mysql/lib/protocol/sequences/Query.js:143:8) 
    at Query.EofPacket (/home/ubuntu/socket/node_modules/mysql/lib/protocol/sequences/Query.js:127:8) 
    at Protocol._parsePacket (/home/ubuntu/socket/node_modules/mysql/lib/protocol/Protocol.js:172:24) 
    at Parser.write (/home/ubuntu/socket/node_modules/mysql/lib/protocol/Parser.js:62:12) 
    at Protocol.write (/home/ubuntu/socket/node_modules/mysql/lib/protocol/Protocol.js:37:16) 
    at Socket.ondata (stream.js:38:26) 
    at Socket.emit (events.js:88:20) 
+0

Что вы получаете, когда вы 'console.log (results)' после 'connection.query (sql, function (err, results) {' в первом разделе кода? – Pebbl

+0

@pebbl i get [{session: ' обращайтесь: 447884001671' }, {сессия: 'контакт: 5551000009484'}, {сессия: 'контакт: 447825846024'}, {сессия: 'контакт: 447960685400'}] –

ответ

2

Ваша проблема является до конца не понимая рамки, в основном проблема здесь имеет место:

for (var i=0; i < results.length; i++) { 
    retrieveContactName(results[i].session, sip, pass, function(value) { 
     sock.write('Conversations '+results[i].session+' '+value+'\n'); 
    }); 
} 

выше не будет работать так, как вы ожидаете, потому что к моменту вашего обратного вызова i не будет иметь ожидаемого значения ... он, скорее всего, будет равен results.length, который даст вам undefined слот в results. Это связано с тем, что for, скорее всего, продолжится и завершит его выполнение до того, как будут вызваны обратные вызовы. Это принцип неблокирования, код не ждет, он продолжается, и ваши обратные вызовы должны быть подготовлены для этого.

Чтобы использовать значение i или любую переменную, которая может изменить ее значение вне области вашего обратного вызова, вам необходимо зафиксировать это значение и сохранить его с помощью обратного вызова. Есть несколько способов сделать это, но самый лучший способ - передать данные, которые требуется вашему обратному вызову, в качестве аргументов —, поэтому вам нужно передать results[i].session (переданный в retrieveContactName) на ваш обратный вызов.

function retrieveContactName(session, user, pass, callback) { 
    var sql = "SELECT `im_from` FROM `im` WHERE `session` = "+connection.escape(session)+" AND `im_to` != "+connection.escape(session)+" AND `sip` = "+connection.escape(user)+" AND `password` = "+connection.escape(pass)+" LIMIT 1"; 
    connection.query(sql, function(err, results) { 
     if (err) winston.warn(err); 
     if (results.length > 0) { 
      callback(results[0].im_from, session); 
     } else { 
      callback(session.replace("contact:",""), session); 
     } 
    }); 
} 

И потом:

for (var i=0; i < results.length; i++) { 
    retrieveContactName(results[i].session, sip, pass, function(value, session) { 
     sock.write('Conversations '+session+' '+value+'\n'); 
    }); 
} 

Очевидно, что это просто быстрый пример, это может быть лучше, чтобы пройти в фактических результатов ряда — в зависимости от того, что вы хотите/потребность.

+0

это все, спасибо за пояснения и кода –

+0

и если я хочу вызвать вторую функцию сейчас, мне просто нужно правильно вставить обратные вызовы? –

+0

@VinceLowe не проблема :) это типичная проблема, с которой вы столкнулись, когда начинаете работать с обратными вызовами - лучший совет - уловить любые значения, которые вам нужны, когда вы их получите. Не полагайтесь на вары, имеющие такое же значение позже ... – Pebbl

0

Результаты [I] может быть вне сферы внутри обратного вызова

case 'getConversations': 
var sip = parts[1]; 
var pass = parts[2].replace(/[\n\r]/g, ''); //strip that carriage return 
var sql = "SELECT DISTINCT(session) FROM im WHERE sip = "+connection.escape(sip)+" AND password = "+connection.escape(pass)+" ORDER BY timestamp DESC"; 
connection.query(sql, function(err, results) { 
    if (err) winston.warn(err); 
    for (var i=0; i < results.length; i++) { 
     retrieveContactName(results[i].session, sip, pass, function(value) { 
      sock.write('Conversations '+results[i].session+' '+value+'\n'); 
     }); 
    } 
}); 

перерыва;

Вы можете разместить console.log (результаты) чуть выше:

sock.write('Conversations '+results[i].session+' '+value+'\n'); 
Смежные вопросы