我在Sequlize中有User和File模型。用户可以拥有多个文件。 我有协会 db.User.hasMany(db.File,{as:' Files',foreignKey:' userId',constraints:false});
我想用几个文件初始化User对象并将其保存到数据库。
我写了下一段代码:
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);
});
});
但我发现了一个错误,有时几个文件与用户无关。
我发现(在nodejs日志中)命令(更新)用于设置这些文件的外键。 但命令没有执行。几个文件的外键(userId)是空的。
我认为问题出在异步查询中。 如何组织代码结构以避免这个错误?
答案 0 :(得分:2)
问题正是您所想的,即异步代码。
您需要移动回调中的函数,否则代码会在创建文件之前运行。
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