Q.all и множество обещаний, похоже, не работают

Я пытаюсь использовать Q для выполнения некоторой работы. Я перебираю и вызываю функцию, которая сохраняет данные в базу данных и возвращает обещание. Как только это будет сделано, мне нужно сделать что-то еще, но Q.all завершается, хотя я вижу, что вызывается каждое разрешение. Я схожу с ума, есть идеи?

Установка:

// save the divisions and then do the division checks
// data.divisions is an array of objects
var promises = [];
data.divisions.forEach(function(dd){
    var d = new grpl.division.Division(dd),
        p = d.save();
    promises.push(p);
});

Q.all(promises)
.then(function(){
    // do some other stuff here
    // this never actually gets called

}).fail(function(err){
    cb(err);
}).done();

А вот d.save()

Division.prototype.save = function(){
    var self = this
        d = Q.defer();

    getPool().getConnection(function(err, db){
        if(err){ d.reject(err); return false; }

        var fields = {
            division_id: self.division_id,
            season_id: self.season_id,
            title: self.title,
            cap: self.cap,
            display_order: self.display_order
        };

        db.query("INSERT INTO division SET ? ON DUPLICATE KEY UPDATE ?", [fields, fields], function(err, result) {
            if(err){ d.reject(err); return false; }
            d.resolve(true);// this does get resolved for each division
        });
    });

    return d.promise;
}

Я понятия не имею, что не так, но он просто останавливается и, похоже, никогда не разрешал мой вызов Q.all.

ОБНОВЛЕНИЕ Похоже, что первоначальный вызов сохранения будет работать правильно, но последующие вызовы сохранения, похоже, разрешают то же обещание, что и первый вызов. Я обернул тело кода сохранения в переменную функцию, которую я вызвал из сохранения, и она работает, но я не уверен на 100%, почему (прототипное наследование - мой запасной вариант, когда JS действительно меня смущает). Любые объяснения или лучшие способы сделать это?

Division.prototype.save = function(){
    var func = function(self){
        var d = Q.defer();

        d.promise.division_id = self.division_id;

        getPool().getConnection(function(err, db){
            if(err){ d.reject(err); return false; }

            var fields = {
                division_id: self.division_id,
                season_id: self.season_id,
                title: self.title,
                cap: self.cap,
                display_order: self.display_order
            };

            db.query("INSERT INTO division SET ? ON DUPLICATE KEY UPDATE ?", [fields, fields], function(err, result) {
                if(err){ d.reject(err); return false; }
                d.resolve(result);
            });
        });

        return d.promise;
    }

    return func(this);
}

person aron.duby    schedule 06.06.2014    source источник
comment
Это работает, если вы вызываете .save напрямую без .all?   -  person loganfsmyth    schedule 06.06.2014
comment
@loganfsmyth не уверен, что вы имеете в виду без all, поскольку save вызывается независимо от all, это просто возвращенные промисы из save, которые добавляются в массив, над которым работает all. Но теперь, когда я говорю, я мог видеть, как он может хранить ссылку на функцию сохранения вместо возвращаемого обещания. Надо будет попробовать, когда вернусь домой.   -  person aron.duby    schedule 07.06.2014
comment
К сожалению, это было не так. Я отредактировал код, чтобы показать свое обновление   -  person aron.duby    schedule 07.06.2014
comment
Извините, мой вопрос: учитывая ваш код, что заставляет вас говорить, что проблема .all, а не что-то еще? Если вы сделаете d.save().then(function(){ ... });, это запустится?   -  person loganfsmyth    schedule 07.06.2014
comment
Если save работает, то можете ли вы устранить проблему, чтобы не включать какую-либо логику вашей БД? Ваш пример сейчас довольно большой.   -  person loganfsmyth    schedule 07.06.2014
comment
после множества изменений и возни, вызов разрешения в d работал правильно для первого вызова, но последующие вызовы действовали на тот же отложенный объект, что и первый вызов, в то время как массив, переданный всем, имел отдельные промисы. Я завернул тело моей функции сохранения в переменную функцию и вернул ей вызов, и теперь все работает нормально. Я предполагаю, что это как-то связано с прототипическим наследованием, но на самом деле понятия не имею.   -  person aron.duby    schedule 07.06.2014
comment
Я подозреваю, что большинство ваших проблем связано с тем, что вы смешиваете обратные вызовы с обещаниями (например, когда вы вызываете getPool().getConnection() и db.query()). Сначала вы должны преобразовать обратные вызовы в стиле Node в промисы. Итак, вместо того, чтобы вручную создавать промис с помощью Q.defer(), взгляните на Q.denodeify() или один из подобных вспомогательных методов (Q.nbind, Q.nfapply).   -  person Sergey K    schedule 07.06.2014


Ответы (1)


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

Division.prototype.save = function(){
    var self = this
        d = Q.defer();

Видишь? Я не знал, пока ваши комментарии не прояснили, что происходит не так.

Division.prototype.save = function(){
    var self = this
                   ^
        d = Q.defer();

Вам не хватает ,, поэтому d — это глобальная переменная, а не save, поэтому каждый раз, когда вы вызываете .save(), вы переписываете глобальную переменную, и все ваши попытки resolve и reject будут разрешать одну и ту же глобальную переменную вместо отложенной. для каждого вызова сохранения.

person loganfsmyth    schedule 07.06.2014
comment
Ах да, автоматическая вставка точки с запятой в JavaScript. Спасибо, JavaScript, вы так полезны! - person Sergey K; 07.06.2014
comment
Да, это было так. Конечно что-то маленькое и глупое. Спасибо за помощь. - person aron.duby; 08.06.2014