Проблема именно в том, о чем вы думаете, асинхронном коде.
Вам нужно переместить функции внутри обратных вызовов, иначе код запустится до создания файла.
JavaScript не ждет, прежде чем перейти к следующей строке, поэтому он будет запускать следующую строку независимо от того, завершена она или нет. У него нет смысла ждать, прежде чем двигаться.
Таким образом, вы в основном добавляете что-то, чего еще не существует, потому что оно не ждет сохранения файла, прежде чем двигаться дальше.
Это сработает, просто переместив код внутри обратных вызовов then
:
var files = [];
var file1 = models.File.build();
file1.name = "JPEG";
file1.save().then(function () {
files.push(file1);
var file2 = models.File.build();
file2.name = "PNG";
file2.save().then(function () {
files.push(file2);
var newUser = models.User.build();
newUser.email = email;
newUser.save().then(function (usr) {
files.forEach(function (item) {
newUser.addFile(item);
});
});
});
});
Но это грязно. Вместо этого вы можете связать обещания следующим образом:
var files = [];
var file1 = models.File.build();
file1.name = "JPEG";
file1.save()
.then(function(file1) {
files.push(file1);
var file2 = models.File.build();
file2.name = "PNG";
return file2.save();
})
.then(function(file2) {
files.push(file2);
var newUser = models.User.build();
newUser.email = email;
return newUser.save();
})
.then(function(newUser) {
files.forEach(function(item) {
newUser.addFile(item);
});
});
Теперь это немного чище, но все еще немного грязно, а также немного сбивает с толку. Таким образом, вы можете использовать функции генератора вместо этого:
var co = require('co');
co(function*() {
var files = [];
var file1 = models.File.build();
file1.name = "JPEG";
yield file1.save();
files.push(file1);
var file2 = models.File.build();
file2.name = "PNG";
yield file2.save();
files.push(file2);
var newUser = models.User.build();
newUser.email = email;
newUser.save();
files.forEach(function(item) {
newUser.addFile(item);
});
});
Теперь это намного лучше.
Посмотрите внимательно, и вы увидите, что происходит. co
принимает функцию генератора, которая в основном является обычной функцией со звездочками *
. Это специальная функция, которая добавляет поддержку yield
выражений.
Выражения yield
в основном ждут вызова обратного вызова then()
, прежде чем двигаться дальше, и если обратный вызов then
имеет аргумент, он также вернет его.
Итак, вы можете сделать что-то вроде:
var gif = yield models.File.create({
name: 'gif'
});
вместо:
models.File.create({
name: 'gif'
}).then(function(gif) {
});
Для этого вам нужно использовать небольшой модуль узла под названием co
, хотя всего лишь npm install --save co
04.10.2016