Knex: 移行でPromiseが期待どおりに動作しない

作成日 2014年06月16日  ·  10コメント  ·  ソース: knex/knex

(これは#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)
question

最も参考になるコメント

したがって、ここでの混乱は、 createTableメソッドがpromiseを返さず、むしろ「thenable」であるSchemaBuilderオブジェクトを返すことです。つまり、 .thenを呼び出します。オブジェクトは有効なA + promiseを返しますが、オブジェクト自体はpromiseではありません。

これは、構文を使用できるようにするために特別に行われました。

  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]);
};

そして物事は仕様で定義されているように機能します。

全てのコメント10件

すでにsecondfirstチェーンしているので、 Promise.all([first, second]);を返す必要はないと思います。 return firstだけやってみてください。 2番目のcreateTablefirstからチェーンされたthenあるため、実行されるため、 Promise.allに追加する必要はありません。とにかくfirstが解決されている間。

promiseの仕様では、promiseが実行されると、それは二度と実行されるべきではなく、 thenを今後呼び出すと、キャッシュされた結果が返されるはずです。 firstsecond両方が満たされている場合、 Promise.all([first, second])は〜何もしないはずです。

return first動作は同じです。つまり、 firstfirst 、およびsecondテーブルを作成しようとしますが、これは_さらに間違っています_。そのシナリオでfirst.thenに渡された関数内の何かを実際に評価するコードであってはなりません。

うーん、それは奇妙に聞こえます。 Promise.allを使用しないと、パフォーマンスが少し向上する可能性があります;)

しかし、ええ、これは間違っているようです。 今のところこれをバグとしてマークし、 @ tgriesserがチャイムを

ハハ、私は移行で1ティック相当のパフォーマンスを特に気にしません:p

申し訳ありませんが、上記で間違ったステートメントを作成しました- return firstはまだ2番目のテーブルを作成するはずです、それは関数の結果で.thenを呼び出した結果がそれを待たないということだけです。 これは、w / e-それでも間違いなくfirstfirstsecond実行しないはずです!

完全に理解しているかどうかわからない:2番目のテーブルが最初のテーブルの作成を待たないのはなぜですか? thenを使用して最初の約束を連鎖させるので、それらは効果的に直列に実行されます。 それは問題ではないはずです。

2番目のテーブルの作成は可能ですが、 exports.up関数の結果はそうではありません。 あなたが呼び出す場合すなわち、 exports.up().then 、それが呼び出すのと同じですfirst.then及びませんsecond.thenそれは_is_ので- first.then

ああ、そこであなたを誤解しました-ええ、あなたはそれについて正しいです!

したがって、ここでの混乱は、 createTableメソッドがpromiseを返さず、むしろ「thenable」であるSchemaBuilderオブジェクトを返すことです。つまり、 .thenを呼び出します。オブジェクトは有効なA + promiseを返しますが、オブジェクト自体はpromiseではありません。

これは、構文を使用できるようにするために特別に行われました。

  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!
このページは役に立ちましたか?
0 / 5 - 0 評価