(这可能是#312的副本)
像这样的迁移文件:
exports.up = function(knex, Promise) {
var first = knex.schema.createTable('first', function(table) {
table.increments('id');
table.string('name');
});
var second = first.then(function() {
return knex.schema.createTable('second', function(table) {
table.increments('id');
table.string('name');
});
});
return Promise.all([first, second]);
};
exports.down = function(knex, Promise) {
};
给出以下输出:
{ __cid: '__cid1',
sql: 'create table "first" ("id" serial primary key, "name" varchar(255))',
bindings: [] }
{ __cid: '__cid2',
sql: 'create table "first" ("id" serial primary key, "name" varchar(255))',
bindings: [] }
{ __cid: '__cid3',
sql: 'create table "second" ("id" serial primary key, "name" varchar(255))',
bindings: [] }
error: duplicate key value violates unique constraint "pg_type_typname_nsp_index"
at Connection.parseE (/home/sohum/node_modules/pg/lib/connection.js:526:11)
at Connection.parseMessage (/home/sohum/node_modules/pg/lib/connection.js:356:17)
at Socket.<anonymous> (/home/sohum/node_modules/pg/lib/connection.js:105:22)
at Socket.EventEmitter.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:745:14)
at Socket.EventEmitter.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:407:10)
at emitReadable (_stream_readable.js:403:5)
at readableAddChunk (_stream_readable.js:165:9)
at Socket.Readable.push (_stream_readable.js:127:10)
我不认为您应该返回Promise.all([first, second]);
,因为您已经将second
到first
。 您能不能只尝试return first
吗? 由于您的第二个createTable
在then
,而first
已链接,因此无需将其添加到Promise.all
,因为它将被执行无论如何,在first
正在解决中。
Promise规范说,一旦实现了Promise,就永远不能再次实现它,并且将来所有then
调用都应返回缓存的结果。 如果first
和second
都已实现,则Promise.all([first, second])
应该是〜no-op。
return first
具有相同的行为-即,它尝试创建first
, first
和second
表,这甚至是错误的,因为应该在那种情况下,永远不会是任何实际评估传递给first.then
的函数内任何内容的代码。
嗯,听起来确实很奇怪。 虽然不使用Promise.all
可以稍微提高性能;)
但是,是的,这似乎是错误的。 我现在将其标记为错误,并等待@tgriesser发出提示音。感谢您的举报!
哈哈,在迁移过程中,我并不特别在乎一滴水的表现:p
抱歉,我在上面的语句中做错了- return first
仍然应该创建第二个表,只是在函数的结果上调用.then
的结果不会等待它。 w / e-应该绝对不要执行first
, first
, second
!
不确定我是否完全理解:第二个表为什么不等待第一个表的创建? 由于您使用then
断开了第一个承诺,因此它们将有效地连续运行。 那不应该是一个问题。
是,第二个表的创建将是,但是exports.up
函数的结果将不会。 即,如果您调用exports.up().then
,则与调用first.then
而不是调用second.then
-因为它是_is_ first.then
!
啊,在那里误会了你-是的,你是对的!
因此,这里的困惑在于createTable
方法不会返回承诺,而是返回SchemaBuilder
对象,该对象是“ thenable”,即在对象上调用.then
对象将返回有效的A +承诺,但对象本身不是承诺。
专门这样做是为了允许您使用以下语法:
return knex.schema.createTable('first', function(table) {
table.increments('id');
table.string('name');
})
.createTable('second', function(table) {
table.increments('id');
table.string('name');
}).then(function() {
// all done
});
它将按顺序在同一连接上按预期运行迁移。
另外,这里不需要Promise.all
,因为这样做可以达到相同的效果:
exports.up = function(knex, Promise) {
return knex.schema.createTable('first', function(table) {
table.increments('id');
table.string('name');
}).then(function() {
return knex.schema.createTable('second', function(table) {
table.increments('id');
table.string('name');
});
});
};
但是,如果您愿意,可以执行以下操作:
exports.up = function(knex, Promise) {
var first = knex.schema.createTable('first', function(table) {
table.increments('id');
table.string('name');
}).then(); // coerce thenable to a promise
var second = first.then(function() {
return knex.schema.createTable('second', function(table) {
table.increments('id');
table.string('name');
});
});
return Promise.all([first, second]);
};
一切都会按照规范定义进行。
好的,这可以解释。 不知道-对无法立即给出直接答案的困惑感到抱歉@SohumB
是的,我们有比这更复杂的依赖图; 这只是一个最小的测试用例! 谢谢您的帮助。
@johanneslumpe
sohum<strong i="8">@diurnal</strong> ~ % cat test.js
var Promise = require('bluebird');
function promises() {
var first = Promise.resolve('wee');
var second = first.then(function() {
console.log('delayin');
return Promise.delay(1000);
}).then(function() {
console.log('done!');
});
return first;
}
promises().then(function() { console.log('yep, first is finished'); });
sohum<strong i="9">@diurnal</strong> ~ % node test.js
delayin
yep, first is finished
done!
最有用的评论
因此,这里的困惑在于
createTable
方法不会返回承诺,而是返回SchemaBuilder
对象,该对象是“ thenable”,即在对象上调用.then
对象将返回有效的A +承诺,但对象本身不是承诺。专门这样做是为了允许您使用以下语法:
它将按顺序在同一连接上按预期运行迁移。
另外,这里不需要
Promise.all
,因为这样做可以达到相同的效果:但是,如果您愿意,可以执行以下操作:
一切都会按照规范定义进行。