Javascript: вложенные обратные вызовы / результаты MySQL - PullRequest
2 голосов
/ 30 ноября 2010

Я уверен, что это основной вопрос, но я некоторое время искал в Google и не могу найти удовлетворительного ответа.

Я привык программировать запросы выбора MySQL на PHP и просто захватывалрезультат, циклически проходя по каждой строке, и внутри цикла выполняйте дальнейшие запросы на основе значений столбцов каждой отдельной строки.

Однако теперь я работаю с кодом на стороне сервера JavaScript, который опирается на объект SQL, гдепередать запрос, а затем функцию обратного вызова, которая будет вызвана после запуска запроса.

Я запутался в некоторых проблемах с областями видимости и в том, как лучше всего это сделать.Например, я не хочу делать что-то вроде:

SQL.query("select * from blah", function(result) { 
  for(var i = 0; i < result.length; i++) {
    SQL.query("select * from blah2 where i =" + result[i].property, function(result2) {
      //now how do I access result from here? I know this isn't scoped correctly
    });
  }
});

Каков стандартный способ написания этого стиля вложенного SQL-запроса без проблем с областями видимости / грязным кодом?Спасибо!

Ответы [ 4 ]

0 голосов
/ 30 ноября 2010

Как уже отмечали другие, result на самом деле будет доступно во вложенном обратном вызове.

Но в этом есть одна хитрость:

... Поскольку вложенный запрос выполняется асинхронно, ваш код фактически сработает связка параллельных запросов - по одному для каждой строки в result - все выполняются одновременно (!).Это почти наверняка не , что вы хотите;и если result действительно очень мало, то все одновременные запросы довольно быстро израсходуют все ваши доступные соединения с БД.

Чтобы исправить это, вы можете использовать что-то вроде этого:

SQL.query("select * from blah", function(result) { 
    handleBlahRow( result, 0 );
});

function handleBlahRow( result, i ) {
    if( !result || (i >= result.length)) return;

    SQL.query("select * from blah2 where i =" + result[i].property, function(result2) {
        // kick off the next query
        handleBlahRow( result, i+1 );

        // result, i, *and* result2 are all accessible here.
        // do whatever you need to do with them
    });
});

Вышеприведенные запросы будут выполнять ваши вложенные запросы по одному.Довольно легко адаптировать вышеприведенное, чтобы ввести ограниченный параллелизм (например, 4 за раз), если вы этого хотите - хотя, вероятно, в этом нет необходимости.

0 голосов
/ 30 ноября 2010

Это очень интересно ... Я никогда не слышал о "javascript на стороне сервера" ... но тем не менее это может помочь немного организовать ваш код.Я использую этот метод для организации своих обратных вызовов ajax-запросов.

на вашем примере это выглядело бы так.как мне нравится организовывать подобные вещи.

0 голосов
/ 30 ноября 2010

Поскольку вы используете серверный Javascript, вы, вероятно, можете использовать forEach. Предполагая, что result instanceof Array == true:

SQL.query("select * from blah", function(result) { 
  result.forEach(function(item, index) {
    SQL.query("select * from blah2 where i = " + item.property, function(result2) {
      console.log(item, index, result); //works as intended
    });
  });
});

Если result просто массив, то это

Array.prototype.forEach.call(result, function(item, index) { // etc...

должен сделать трюк.

0 голосов
/ 30 ноября 2010

result будет доступен во втором обратном вызове, вот так замыкает в работе JavaScript, функции имеют доступ ко всем переменным во внешних областях, в которых они были определены.

function outer() {
    var foo = 1;
    function inner() { // inherits the scope of outer
        var bla = 2;
        console.log(foo); // works!

        // another function in here well inherit both the scope of inner AND outer, and so on
    }
    inner();
    console.log(bla); // doesn't work, raises "ReferenceError: bla is not defined"
}
outer();

Теперь, говоря о проблеме, i не будет указывать на правильное значение, оно также будет унаследовано для второго обратного вызова, но оно является ссылкой и поэтому будет иметь неправильное значение.

Исправлено создание другого замыкания:

SQL.query("select * from blah", function(result) { 
  for(var i = 0; i < result.length; i++) {
    (function(innerResult) { // anonymous function to provide yet another scope
        SQL.query("select * from blah2 where i =" + innerResult.property, function(result2) {
          // innerResult has the correct value
        });
    })(result[i]); // pass the current result into the function
  }
});

Или дополнительная функция:

function resultThingy(result) {
   SQL.query("select * from blah2 where i =" + result.property, function(result2) {
       // result has the correct value
   });
}

SQL.query("select * from blah", function(result) { 
  for(var i = 0; i < result.length; i++) {
    resultThingy(result[i]);
  }
});
...