(Это может быть дубликат № 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
.
Спецификация обещания гласит, что после выполнения обещания оно никогда не должно выполняться снова, и все будущие вызовы then
должны возвращать кешированный результат. Если first
и second
оба выполнены, то Promise.all([first, second])
должно быть ~ нерабочим.
return first
ведет себя так же - то есть пытается создать таблицы first
, first
и second
, что _еще более неверно_, как и должно быть никогда не должен быть код, который фактически оценивает что-либо внутри функции, переданной в first.then
в этом сценарии.
Хм, ладно, звучит странно. Однако отказ от использования Promise.all
может немного повысить производительность;)
Но да, это кажется неправильным. Я сейчас отмечу это как ошибку и подожду, пока не
Ха-ха, меня не особо заботит производительность одного тика в моих миграциях: p
Извините, я сделал неверное утверждение выше - return first
все равно должен создать вторую таблицу, просто результат вызова .then
для результата функции не дождется этого. Что, ж / д - он все равно определенно не должен делать first
, first
, second
!
Не уверен, что полностью понимаю: почему бы второй таблице не дождаться создания первой? Поскольку вы связываете первое обещание с помощью then
они будут эффективно выполняться последовательно. Это не должно быть проблемой.
Да, вторая таблица будет создана, но результат функции exports.up
нет. То есть, если вы вызываете exports.up().then
, это то же самое, что и вызов first.then
а не second.then
- потому что это _is_ first.then
!
Ах, там вас неправильно поняли - да, в этом вы правы!
Таким образом, путаница здесь заключается в том, что метод createTable
не возвращает обещание, а возвращает объект SchemaBuilder
, который является "пригодным для использования", т.е. вызывает .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
, который является "пригодным для использования", т.е. вызывает.then
на объект вернет действительное обещание A +, но сам объект не является обещанием.Это было сделано специально для того, чтобы вы могли использовать синтаксис:
который должен запускать миграции, как ожидалось, в одном и том же соединении последовательно.
Кроме того, здесь нет необходимости в
Promise.all
, поскольку это приведет к тому же:хотя при желании можно было бы:
и все будет работать, как указано в спецификации.