NodeJS + MongoJS: проблема с вложенными обратными вызовами

Я все еще n00b с NodeJS, поэтому этот вопрос может быть несколько элементарным.

Я использую MongoJS для чтения двух логически связанных коллекций. Первый find() возвращает значение, которое я передаю второму find() для получения необходимой информации.

Я пробовал несколько стратегий, последняя из которых (фрагмент № 1) — это класс, который я экспортирую.

До этого у меня была только функция, которая выполняла return, возвращая желаемое значение, то есть "config[0]".

В этом коде все, что я сделал, это присвоил атрибуту «sapConfig» слово «test», но когда я выполняю этот код, значение «sapConfig» всегда равно «null» после вызова метода «get_config()» и — самое странное из всего - ссылка на "this.sapConfig = 'test'" выдает ошибку, т.е. "Невозможно установить свойство 'sapConfig' из неопределенного".

Когда у меня был код простой функции с оператором return (фрагмент № 2), ошибок не генерировалось, но возвращаемое значение всегда было «неопределенным», хотя операторы console.log() показывают, что значение возвращаемой переменной имеет желаемое значение. Что дает?

Фрагмент кода №1: возвращает объект

"use strict";

var mongojs = require('mongojs'); // MongoDB API wrapper

module.exports = function(regKey) {

    this.regKey = regKey;
    this.sapConfig = null;

    this.get_config = function() {

        // Read SAP connection information from our MONGO db
        var db = mongojs('mongodb://localhost/MIM', ['Configurations','Registrations']);

        db.Registrations.find({ key: this.regKey }, function(err1, registration){
            console.log('Reg.find()');
            console.log(registration[0]);
            db.Configurations.find({ type: registration[0].type }, function(err2, config){
                console.log('Config.find()');
                console.log('config=' + config[0].user);
                this.sapConfig = 'test';
            });
        });
    }

    this.get_result = function() {
        return this.sapConfig;
    }
}

Опять же, код во фрагменте № 1, когда я вызываю «get_config()», приводит к ошибке при выполнении строки «this.sapConfig = 'test'».

Однако после этой ошибки я могу выполнить «obj.get_result()» и получить значение, которым оно было инициализировано, т. е. null. Другими словами, тот же код не генерирует ошибку, говорящую о том, что «это» не определено как .in в методе «get_config()».

Фрагмент кода № 2: Использование инструкции «return»

"use strict";

var mongojs = require('mongojs'); // MongoDB API wrapper

module.exports = function(regKey) {

        // Read SAP connection information from our MONGO db
        var db = mongojs('mongodb://localhost/MIM', ['Configurations','Registrations']);

        db.Registrations.find({ key: regKey }, function(err1, registration){
            console.log('Reg.find()');
            console.log(registration[0]);
            db.Configurations.find({ type: registration[0].type }, function(err2, config){
                console.log('Config.find()');
                console.log('config=' + config[0].user);
                return config[0].user;
            });
        });
}

Когда я получаю возвращаемое значение и проверяю его, оно «не определено». Например, на Node CL я выдаю следующие команды:

var config = require('./config') // The name of the module above
> var k = config('2eac44bc-232d-4667-bd24-18e71879f18c')
undefined <-- this is from MongoJS; it's fine
> Reg.find() <-- debug statement in my function
{ _id: 589e2bf64b0e89f233da8fbb,
  key: '2eac44bc-232d-4667-bd24-18e71879f18c',
  type: 'TEST' }
Config.find()
config=MST0025
> k <-- this should have the value of "config[0]"
undefined

Вы можете видеть, что запросы были успешными, но значение «k» равно «undefined». Что тут происходит?

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

Заранее спасибо!


person Ishmael    schedule 11.02.2017    source источник
comment
Смотрите мой новый пример в моем ответе на вторую часть :) Ура.   -  person matt    schedule 11.02.2017


Ответы (1)


this.sapConfig недоступен. Это потому, что this относится к текущей функции. Что мне нравится делать, так это иметь переменную, которая ссылается на экземпляр функции, в котором, как вы знаете, находится sapConfig.

Ex:

function Foo() {
   var self = this;

   this.test = "I am test";

   var bar = function(){
     return function(){
       console.log(this.test); //outputs undefined (because this refers to the current function scope)
       console.log(self.test); //outputs "I am test";
     }
   }
}

Вот ваш первый фрагмент кода с реализованным моим примером:

"use strict";

var mongojs = require('mongojs'); // MongoDB API wrapper

module.exports = function(regKey) {
  var self = this;

  this.regKey = regKey;
  this.sapConfig = null;

  this.get_config = function() {

    // Read SAP connection information from our MONGO db
    var db = mongojs('mongodb://localhost/MIM', ['Configurations', 'Registrations']);

    db.Registrations.find({ key: this.regKey }, function(err1, registration) {
      console.log('Reg.find()');
      console.log(registration[0]);
      db.Configurations.find({ type: registration[0].type }, function(err2, config) {
        console.log('Config.find()');
        console.log('config=' + config[0].user);
        self.sapConfig = 'test';
      });
    });
  }

  this.get_result = function() {
    return self.sapConfig;
  }
}

Для вашего второго фрагмента. Вы пытаетесь вернуть значение из вложенного обратного вызова. Поскольку вложенные функции асинхронны, вы не можете этого сделать.

Вот как мне нравится возвращать значения из вложенных обратных вызовов:

Ex2:

//Function example
var functionWithNested = function(done) {
  //Notice the done param. 
  //  It is going to be a function that takes the finished data once all our nested functions are done.

  function() {
    //Do things
    function() {
      //do more things
      done("resultHere"); //finished. pass back the result.
    }();//end of 2nd nested function
  }(); //end of 1st nested function
};

//Calling the function
functionWithNested(function(result) {
  //Callback
  console.log(result); //resultHere
})

Вот ваш код, использующий этот пример:

"use strict";

var mongojs = require('mongojs'); // MongoDB API wrapper

module.exports = function(regKey, done) {

  // Read SAP connection information from our MONGO db
  var db = mongojs('mongodb://localhost/MIM', ['Configurations', 'Registrations']);

  db.Registrations.find({ key: regKey }, function(err1, registration) {
    console.log('Reg.find()');
    console.log(registration[0]);
    db.Configurations.find({ type: registration[0].type }, function(err2, config) {
      console.log('Config.find()');
      console.log('config=' + config[0].user);
      done(config[0].user);
    });
  });
}

//Then wherever you call the above function use this format
// if config is the name of the function export above...

new Config().(regKey, function(result){

    console.log(result); //config[0].user value
})

Много-много кода, но я надеюсь, что вы смогли следовать ему. Позвольте мне знать, если у вас есть еще вопросы! Ваше здоровье.

person matt    schedule 11.02.2017
comment
Превосходно! Сработало как волшебство, и теперь, когда вы объяснили это, это имеет смысл. Знаете ли вы, почему другой фрагмент возвращал значение undefined, т. е. почему оператор return не работал должным образом? - person Ishmael; 11.02.2017
comment
Рад, что это имело смысл для вас. Для вашей проблемы с оператором возврата: вы не можете вернуть значение из вложенного обратного вызова. Я добавлю еще один пример того, как мне нравится возвращать значения из вложенных обратных вызовов. Просто дайте несколько :) - person matt; 11.02.2017
comment
Да! Идеально! Это имеет смысл. Я не думал асинхронно. Отличная информация. Большое спасибо! - person Ishmael; 12.02.2017
comment
@Ishmael Добро пожаловать. Пожалуйста, отметьте мой ответ как решение :) Удачи в разработке :) - person matt; 12.02.2017