javascript - 在调用 `.then` 之后执行副作用是否需要 Promises A+ promises?

标签 javascript promise

我被 Knex API for building a schema 的方式绊倒了在您调用 .then 之前实际上不会创建表。

例如,这段代码实际上不会影响数据库:

knex.schema.createTable('users', table => {
  table.string('name')
})

但是这段代码将:

knex.schema.createTable('users', table => {
  table.string('name')
}).then(console.log.bind(console))

这种行为是(在调用 .then 之前不做任何事情):

a) Promises A+ spec 要求

b) 被 Promises A+ spec 禁止

c) 未指定

?

我阅读了规范,似乎行为未指定,但我不确定。这似乎太重要了,不能不具体说明。

更新

请参阅@Vohuman 的回答:Knex 架构构建器上的 then 方法首先执行副作用,然后返回 promise 。因此,即使我的问题的答案是(b),Knex 也不会违反规范。尽管在这种情况下选择 then 作为方法名称非常具有误导性。

最佳答案

这并不完全是“错误”,尽管它并不常见。 Knex 需要 .then,因为它必须能够知道查询何时完成,而不是在构建过程中。

Example from the docs (添加评论):

knex.select('name').from('users')    
  .where('id', '>', 20)              // Can I issue the query yet?
  .andWhere('id', '<', 200)          // Okay I'll...oh, you have more conditions.
  .limit(10)                         // Hey, I'm here, still ready...
  .offset(x)                         // Just let me know when you want me to--
  .then(function(rows) {             // OH OKAY I'll issue it now.
    return _.pluck(rows, 'name');
  })

Google 的 API.js 助手 follows this pattern too ,专门针对即时查询与批量查询:

When you create a request with the intention of adding it to a batch, do not invoke its then method until after the request has been added to the batch. If the then method is invoked before the request is added, the request is sent immediately instead of as part of the batch.

作为SLaks指出,这在文档中的任何地方都没有明确指定:为了使对象成为 Promises/A+兼容,它必须有一个名为 then 的方法,具有正确的语义和返回值,并且没有任何内容指定 then 不能有额外的行为。这自然会禁止这些 API 库将 then 方法重命名为更合适的名称,例如 thenIssueRequestthenGetResponse。 (您可以添加别名,但then 必须存在。)

作为 API 设计者,唯一的选择是将 promise 的创建与 then 的链接分开,但需要注意的是几乎每次调用 then 都会在它之前或包装它有一个额外的方法调用。因为 then 是访问结果的唯一方法,所以我可以理解针对常见情况进行优化会如何导致删除额外的方法。

fluentApi.createRequest().parameterA(1).parameterB(2).issue().then(...);
// or
fluentApi.issue(fluentApi.createRequest().parameterA(1).parameterB(2)).then(...);

最后,请记住,您应该始终在某个时刻捕获 Promise,这会触发请求:

knex.schema.createTable('users', table => {
  table.string('name')
}).catch(console.log.bind(console));

...还有那个both arguments to then are optional , 所以如果你坚持跳过错误处理你甚至可以有一个空的 then:

knex.schema.createTable('users', table => {
  table.string('name')
}).then(null);


knex.schema.createTable('users', table => {
  table.string('name')
}).then();

关于javascript - 在调用 `.then` 之后执行副作用是否需要 Promises A+ promises?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38730850/

相关文章:

javascript - jQuery 滚动事件未触发

javascript - ReactJS - 图像未显示在 Material 表的自定义列中

mysql - Knex 创建数据库并向其中插入数据

javascript - 链式 jquery deferred.then() 未返回正确的 promise

Firebase 云函数 - 在 OnUpdate 云触发器中更新不同的对象

javascript - 从 javascript 调用 Rails 操作

javascript - 如何调整内容以自动适应屏幕大小?

javascript - 如何在React中使用Highcharts绘制带有经度和纬度的气泡图

javascript - 为什么 deferred 的 'then' 回调先于嵌套 AJAX 的成功回调?

javascript - axios 调用不返回 promise