Требуется помощь с переменными области видимости JavaScript / ООП и функциями обратного вызова - PullRequest
4 голосов
/ 18 мая 2010

Я думаю, что эта проблема выходит за рамки типичных переменных областей действия и замыканий, или, может быть, я идиот. Здесь все равно идет ...

Я создаю кучу объектов на лету в плагине jQuery. Объект выглядит примерно так

function WedgePath(canvas){
    this.targetCanvas = canvas;
    this.label;
    this.logLabel = function(){ console.log(this.label) }
}

плагин jQuery выглядит примерно так

(function($) {
  $.fn.myPlugin = function() {

  return $(this).each(function() {

     // Create Wedge Objects
     for(var i = 1; i <= 30; i++){ 
      var newWedge = new WedgePath(canvas);
      newWedge.label = "my_wedge_"+i;
      globalFunction(i, newWedge]);
     } 
    });
  }
})(jQuery);

Итак ... плагин создает кучу объектов wedgeObject, затем вызывает для каждого из них «globalFunction», передавая последний экземпляр WedgePath. Глобальная функция выглядит следующим образом.

function globalFunction(indicator_id, pWedge){

    var targetWedge = pWedge; 
    targetWedge.logLabel();

}

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

function globalFunction(indicator_id, pWedge){

        var targetWedge = pWedge; 

        someSql = "SELECT * FROM myTable WHERE id = ?";
        dbInterface.executeSql(someSql, [indicator_id], function(transaction, result){

            targetWedge.logLabel();

        })

    }

Здесь много чего происходит, поэтому я объясню. Я использую хранилище базы данных на стороне клиента (я называю это WebSQL). 'dbInterface' - экземпляр простого созданного мной javascript-объекта, который обрабатывает основы взаимодействия с базой данных на стороне клиента [показано в конце этого вопроса]. метод executeSql принимает до 4 аргументов

  • Строка SQL
  • необязательный массив аргументов
  • опциональный обработчик onSuccess
  • необязательный обработчик onError (в этом примере не используется)

Что мне нужно сделать, так это: когда запрос WebSQL завершен, он берет некоторые из этих данных и манипулирует некоторыми атрибутами определенного клина. Но когда я вызываю 'logLabel' для экземпляра WedgePath внутри обработчика onSuccess, я получаю метку самого последнего экземпляра WedgePath, который был создан еще в коде плагина.

Теперь я подозреваю, что проблема заключается в var newWedge = new WedgePath(canvas); линия. Поэтому я попытался вставить каждый newWedge в массив, который, по моему мнению, не позволил бы этой строке заменять или перезаписывать экземпляр WedgePath на каждой итерации ...

wedgeArray = [];

// Inside the plugin...
for(var i = 1; i <= 30; i++){ 
    var newWedge = new WedgePath(canvas);
    newWedge.label = "my_wedge_"+i;
    wedgeArray.push(newWedge);
} 

for(var i = 0; i < wedgeArray.length; i++){
    wedgeArray[i].logLabel()
}

Но опять же, я получаю последний экземпляр WedgePath для создания.

Это сводит меня с ума. Я прошу прощения за длину вопроса, но я хотел быть максимально ясным.

END

=============================================== ===============

Кроме того, вот код для объекта dbInterface, если он уместен.

function DatabaseInterface(db){

 var DB = db;

 this.sql = function(sql, arr, pSuccessHandler, pErrorHandler){

  successHandler = (pSuccessHandler) ? pSuccessHandler : this.defaultSuccessHandler;
  errorHandler = (pErrorHandler) ? pErrorHandler : this.defaultErrorHandler;

  DB.transaction(function(tx){

   if(!arr || arr.length == 0){
    tx.executeSql(sql, [], successHandler, errorHandler);
   }else{
    tx.executeSql(sql,arr, successHandler, errorHandler)
   }

  });      
 }

 // ----------------------------------------------------------------
 // A Default Error Handler
 // ----------------------------------------------------------------

 this.defaultErrorHandler = function(transaction, error){
  // error.message is a human-readable string.
     // error.code is a numeric error code
     console.log('WebSQL Error: '+error.message+' (Code '+error.code+')');

     // Handle errors here
     var we_think_this_error_is_fatal = true;
     if (we_think_this_error_is_fatal) return true;
     return false;
 }


 // ----------------------------------------------------------------
 // A Default Success Handler
 // This doesn't do anything except log a success message
 // ----------------------------------------------------------------

 this.defaultSuccessHandler = function(transaction, results)
  {
      console.log("WebSQL Success. Default success handler. No action taken.");
  }    
}

Ответы [ 2 ]

3 голосов
/ 19 мая 2010

Я думаю, это связано с тем, что хранилище базы данных на стороне клиента работает асинхронно, как при вызове AJAX. Это означает, что он не останавливает цепочку вызовов для ожидания результата от вызванного метода.

В результате механизм javascript завершает цикл for перед запуском globalFunction.

Чтобы обойти это, вы можете выполнить запрос db внутри замыкания.

function getDataForIndicatorAndRegion(indicator_id, region_id, pWedge){ 
    return function (targetWedge) { 
        someSql = "SELECT dataRows.status FROM dataRows WHERE indicator_id = ? AND region_id = ?"; 
        dbInterface.sql(someSql, [indicator_id, region_id], function(transaction, result) {
            targetWedge.changeColor(randomHex());
        });
    }(pWedge);
}

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

РЕДАКТИРОВАТЬ: Обновлен код из комментариев. И внес изменения в это. Функция обратного вызова, возможно, не должна вызываться самостоятельно. Если он вызывает сам, результат функции передается в качестве аргумента. Также, если это не работает, попробуйте передать другие аргументы.

0 голосов
/ 18 мая 2010

Я подозреваю, что ваша проблема в измененном закрытии, происходящем внутри globalFunction:

function(transaction, result){

        targetWedge.logLabel();

    })

читать это

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...