(Dies kann ein Duplikat von # 312 sein.)
Eine Migrationsdatei wie folgt:
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) {
};
gibt folgende Ausgabe:
{ __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)
Ich denke nicht, dass Sie Promise.all([first, second]);
, da Sie bereits second
mit first
verkettet haben. Könnten Sie bitte versuchen, nur return first
? Da sich Ihr zweites createTable
in einem then
befindet, das mit first
verkettet ist, müssen Sie es nicht zu Promise.all
hinzufügen, da es ausgeführt wird sowieso, während first
aufgelöst wird.
Die Versprechensspezifikation besagt, dass ein einmal erfülltes Versprechen nie wieder erfüllt werden sollte und alle zukünftigen Aufrufe von then
das zwischengespeicherte Ergebnis zurückgeben sollten. Wenn first
und second
beide erfüllt sind, sollte Promise.all([first, second])
~ ein No-Op sein.
return first
hat das gleiche Verhalten - dh es wird versucht, die Tabellen first
, first
und second
erstellen, was sogar noch falscher ist, als es sollte Seien Sie niemals ein Code, der tatsächlich etwas innerhalb der Funktion auswertet, die in diesem Szenario an first.then
wurde.
Ähm ok das klingt komisch. Wenn Sie Promise.all
dies die Leistung geringfügig steigern;)
Aber ja, das scheint falsch zu sein. Ich werde dies vorerst als Fehler markieren und warten, bis
Haha, mir ist die Leistung eines Ticks bei meinen Migrationen nicht besonders wichtig: p
Entschuldigung, ich habe oben eine falsche Aussage gemacht - return first
sollte immer noch die zweite Tabelle erstellen. Es ist nur so, dass das Ergebnis des Aufrufs von .then
für das Ergebnis der Funktion nicht darauf wartet. Was, w / e - es sollte definitiv immer noch nicht first
, first
, second
tun!
Ich bin mir nicht sicher, ob ich das vollständig verstehe: Warum sollte der zweite Tisch nicht auf die Erstellung des ersten warten? Da Sie das erste Versprechen mit then
verketten, werden sie effektiv in Serie ausgeführt. Das sollte kein Problem sein.
Die Erstellung der zweiten Tabelle wird zwar durchgeführt, das Ergebnis der Funktion exports.up
jedoch nicht. Das heißt, wenn Sie exports.up().then
anrufen, ist es dasselbe wie first.then
und nicht second.then
- weil es _is_ first.then
!
Ah, ich habe dich dort missverstanden - ja, da hast du recht!
Die Verwirrung hier ist also, dass die createTable
-Methode kein Versprechen zurückgibt, sondern ein SchemaBuilder
-Objekt zurückgibt, das ein "thenable" ist, dh .then
auf dem aufruft Das Objekt gibt ein gültiges A + Versprechen zurück, aber das Objekt selbst ist kein Versprechen.
Dies wurde speziell durchgeführt, um Ihnen die Verwendung der Syntax zu ermöglichen:
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
});
Dadurch sollten die Migrationen wie erwartet nacheinander auf derselben Verbindung ausgeführt werden.
Außerdem sind hier keine Promise.all
erforderlich, da dies dasselbe bewirken würde:
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');
});
});
};
Wenn Sie möchten, können Sie Folgendes tun:
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]);
};
und die Dinge würden wie in der Spezifikation definiert funktionieren.
Ok, das erklärt das. Wusste das nicht - Entschuldigung für die Verwirrung, dass ich nicht sofort eine klare Antwort geben konnte
Ja, wir haben kompliziertere Abhängigkeitsgraphen als diese; Dies war nur ein minimaler Testfall! Danke für die Hilfe.
@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!
Hilfreichster Kommentar
Die Verwirrung hier ist also, dass die
createTable
-Methode kein Versprechen zurückgibt, sondern einSchemaBuilder
-Objekt zurückgibt, das ein "thenable" ist, dh.then
auf dem aufruft Das Objekt gibt ein gültiges A + Versprechen zurück, aber das Objekt selbst ist kein Versprechen.Dies wurde speziell durchgeführt, um Ihnen die Verwendung der Syntax zu ermöglichen:
Dadurch sollten die Migrationen wie erwartet nacheinander auf derselben Verbindung ausgeführt werden.
Außerdem sind hier keine
Promise.all
erforderlich, da dies dasselbe bewirken würde:Wenn Sie möchten, können Sie Folgendes tun:
und die Dinge würden wie in der Spezifikation definiert funktionieren.