2017-02-24 74 views
1

我被告知,Promise.all无法保证Promise.all能够解决其承诺。但是,我不知道它不能按照Promise.all native docs的顺序解决。用knex迁移承诺所有比赛条件

因此,下面的方法来knex迁移不应该工作,因为messages有一个用户表的引用。

然而,我从来没有遇到过一次实例,在几次迁移中,出现了竞争条件的错误。意思是,好像Promise.all根据索引位置决定。

所以,我的问题是:下面的代码片段容易出现竞争状态吗?

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'); 
     }), 

这是更好的方法吗?

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

你不需要在你的第二个片段中使用'Promise.all'。 – 4castle

+0

假设这些是XHR调用,它们将在您退出函数范围后立即启动。这意味着XHR请求将同时运行。这可能是因为你很幸运,请求的顺序完全按照你想要的方式完成,但是如果'createTable('users')'需要在'createTable('messages')'之前执行',那么你应该使用'.then()':'knex.schema.createTable('users',...)。then(()=> {knex.schema.createTable('messages')});'。 –

回答

1

既然你的依赖,在你需要已创建的第一个表,然后才能在第二个表引用它,你应该使用then三通。

Promise.all是否会看到它的承诺是否按索引顺序解决,与Promise.all本身无关,但是以个体承诺作为参数传递给它。虽然您可以期望JavaScript(而不是Promise.all)按顺序评估参数列表,但您一般无法知道哪些承诺会首先解决。这由个人承诺决定,而不是由Promise.all决定。

就你的情况而言,这些个体承诺会做类似的事情,即创建一个表,并且你的数据库引擎可能会按顺序处理这些语句,而没有并发性,你可能会在实践中看到承诺总是按照你的顺序列出它们,但依靠这种做法是不好的做法。

请注意,如果您只将一个承诺传递给Promise.all,则可以跳过该Promise.all并立即将then应用于该单个承诺。

+0

为了简洁起见,我只列出了我的许多承诺之一。谢谢你的解释。 – Growler

0

我期待这段代码在迁移文件中,默认情况下会创建隐式事务。所以,因为查询被发送到同一个连接,它们将不会被并行解析。

在这种情况下,数据库驱动程序(至少pg)实际上会缓存第二个查询,并在将第二个查询发送到数据库服务器之前等待,直到解决第一个查询。

唯一重要的是执行这两个查询并将其发送到pg-driver。

由于Promise.all不保证它会在knex.schema.createTable('messages',...)之前执行knex.schema.createTable('users',...)查询,这意味着理论上有可能第一个代码失败。


TL;博士第一种方法是不容易出现竞争情况,但如果查询在错误的顺序执行时可能会失败。第二种方法更好。