2017-02-24 6 views
1

Mir wurde gesagt, dass es keine Garantie in der Reihenfolge gibt, in der ein Promise.all seine Versprechungen löst. Ich sehe jedoch nicht, dass es sich nicht in der Reihenfolge von der Promise.all native docs löst.Alle Rennbedingungen mit Knex Migrationen versprechen

Daher sollte der folgende Ansatz für Knex-Migrationen nicht funktionieren, da messages einen Verweis auf Benutzer Tabelle hat.

Dennoch habe ich noch nie eine Instanz von mehreren Migrationen gesehen, bei denen ein Fehler mit einer Race Condition aufgetreten ist. Das heißt, es scheint, als ob Promise.all je nach Indexposition aufgelöst wird.

Also, meine Frage ist: ist das folgende Schnipsel anfällig für eine Race Condition?

return Promise.all([ 
     knex.schema.createTable('users', function(table) { 
     table.increments().primary(); 
     ... 
     }), 
     knex.schema.createTable('messages', function(table) { 
     table.increments().primary(); 
     table.bigInteger('user_id').unsigned().index() 
      .references('id').inTable('users'); 
     }), 

Und ist das der bessere Ansatz?

return Promise.all([ 
     knex.schema.createTable('users', function(table) { 
     table.increments().primary(); 
     ... 
     }), 
    ]).then(function() { 
     return Promise.all([ 
     knex.schema.createTable('messages', function(table) { 
      table.increments().primary(); 
      table.bigInteger('user_id').unsigned().index() 
      .references('id').inTable('users'); 
     }), 
     }); 
    }) 
+0

Sie müssen "Promise.all" nicht in Ihrem zweiten Snippet verwenden. – 4castle

+0

Angenommen, dies sind XHR-Aufrufe, werden sie initiiert, sobald Sie den Funktionsumfang verlassen.Dies bedeutet, dass die XHR-Anforderungen gleichzeitig ausgeführt werden. Es kann sein, dass Sie Glück haben und die Reihenfolge der Anfragen genau so ist, wie Sie es wollen, aber wenn 'createTable ('Benutzer') 'vor' createTable ('Nachrichten') 'ausgeführt werden muss, dann Sie sollte ein '.then()': 'knex.schema.createTable ('users', ...) verwenden, dann (() => {knex.schema.createTable ('messages')});'. –

Antwort

1

Da Sie eine Abhängigkeit haben, dass müssen Sie die erste Tabelle erstellt wurden, bevor Sie es in der zweiten Tabelle verweisen können, sollten Sie die then -Wege verwenden.

Ob Promise.all seine Versprechen in der Indexreihenfolge auflösen wird oder nicht, hat nichts mit Promise.all selbst zu tun, aber mit den einzelnen Versprechen, die ihm als Argumente übergeben wurden. Während Sie erwarten können, dass JavaScript (nicht Promise.all) die Argumentliste der Reihe nach auswertet, können Sie im Allgemeinen nicht wissen, welche dieser Versprechen zuerst gelöst wird. Dies wird durch diese individuellen Versprechen bestimmt, nicht durch Promise.all. Wie in Ihrem Fall machen diese einzelnen Versprechen eine ähnliche Sache, dh erstellen Sie eine Tabelle, und Ihre Datenbank-Engine wird diese Anweisungen wahrscheinlich in der Reihenfolge verarbeiten, ohne Nebenläufigkeit, könnten Sie in der Praxis sehen, dass die Versprechen immer in der Reihenfolge Sie auflösen aufgelistet, aber es wäre schlechte Praxis, sich darauf zu verlassen.

Beachten Sie, dass wenn Sie ein Array mit nur einem Versprechen in Promise.all übergeben, können Sie einfach überspringen Promise.all und wenden Sie die then sofort auf diese einzige Versprechen.

+0

Ich habe nur eines meiner vielen Versprechen aus Gründen der Kürze dort aufgeführt. Vielen Dank für die Erklärung. – Growler

0

Ich erwarte, dass dieser Code in der Migrationsdatei ist, die implizite Transaktion standardmäßig erstellt. Da Abfragen an dieselbe Verbindung gesendet werden, werden sie nicht parallel aufgelöst.

In diesem Fall puffert der Datenbanktreiber (mindestens pg) die zweite Abfrage und wartet, bis die erste Abfrage gelöst ist, bevor die zweite Abfrage an den Datenbankserver gesendet wird.

Es kommt nur darauf an, in welcher Reihenfolge diese 2 Abfragen ausgeführt und an den pg-Treiber gesendet werden.

Da Promise.all garantiert nicht, dass es knex.schema.createTable('users',...) Abfrage vor dem knex.schema.createTable('messages',...) bedeutet ausführen wird es, dass es theoretisch möglich ist, dass der erste Code fehl.


tl; dr erster Ansatz nicht anfällig ist Bedingung zu laufen, aber es kann fehlschlagen, wenn die Abfragen in der falschen Reihenfolge ausgeführt werden. Der zweite Ansatz ist besser.

Verwandte Themen