Promises是调用`.then`后执行副作用所需的A+Promises吗
Are Promises A+ promises required to execute side effects AFTER `.then` is called?
我被用于构建模式的Knex API在调用.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+规范要求
b) 被Promises A+规范禁止
c) 未指定
我阅读了规范,似乎行为没有具体说明,但我不确定。这一点似乎太重要了,无法具体说明。
更新
请参阅@Vohuman的回答:Knex架构生成器上的then
方法首先执行副作用,然后返回promise。因此,即使我的问题的答案是(b)Knex也不会违反规范。尽管在这种情况下选择then
作为方法名称是非常误导的。
这并不完全是"错误的",尽管它并不常见。Knex需要.then
,因为它必须能够判断查询何时完成,而不是中期构建。
文档示例(添加注释):
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');
})
谷歌的API.js助手也遵循这种模式,特别是针对即时查询和批量查询:
当您创建一个请求以将其添加到批处理中时,请在将该请求添加到批中之前不要调用其
then
方法。如果在添加请求之前调用then
方法,则会立即发送请求,而不是作为批处理的一部分。
正如SLaks所指出的,这在文档中的任何地方都没有明确指定:为了使对象符合Promises/A+,它必须有一个名为then
的方法,该方法具有正确的语义和返回值,并且没有任何内容指定then
不能有其他行为。这自然会禁止这些API库将then
方法重命名为更合适的方法,如thenIssueRequest
或thenGetResponse
。(您可以添加别名,但then
必须存在。)
作为一名API设计师,唯一的选择是将promise的创建与then
的链接分开,但需要注意的是,几乎每个对then
的调用都会有一个额外的方法调用在其之前或包装它。因为then
是访问结果的唯一方式,所以我可以理解为常见情况进行优化会如何导致删除额外的方法。
fluentApi.createRequest().parameterA(1).parameterB(2).issue().then(...);
// or
fluentApi.issue(fluentApi.createRequest().parameterA(1).parameterB(2)).then(...);
最后,请记住,您应该始终在某个时刻catch
a Promise,这将触发请求:
knex.schema.createTable('users', table => {
table.string('name')
}).catch(console.log.bind(console));
并且then
的两个参数都是可选的,所以如果你坚持跳过错误处理,你甚至可以有一个空的then
:
knex.schema.createTable('users', table => {
table.string('name')
}).then(null);
knex.schema.createTable('users', table => {
table.string('name')
}).then();
此行为是错误的;调用then()
除了promise本身(即执行回调)之外不应该有任何副作用。
然而,规范实际上并没有对此做任何说明。
knex
是一个查询生成器。then
只是一个助手函数,它执行生成的[SQL]语句,并在后台调用promise对象的then
函数。如果用.toString
函数替换then
,则会得到生成的字符串。这里的then
不是promise对象的方法。
来自knex
源代码:
Target.prototype.then = function(/* onFulfilled, onRejected */) {
const result = this.client.runner(this).run()
return result.then.apply(result, arguments);
};
- 可以简化嵌套的延迟Q Promises解析吗
- 将JS文件解析为PHP的副作用是什么
- Working with Ajax Promises / Deferred
- ExpressJS/NodeJS/Promises:从promise链提前返回
- 用Promises返回的数据替换出现的文本
- JS Promises如何在内部工作
- 尝试使用Promises删除记录
- Backbone JS Promises在模型上设置属性之前解析
- 在.settle()(或等效项)中,从Promises数组中断开
- Coffeescript 隐式返回对性能和副作用的影响
- jQuery Promises with chained setTimeouts
- 在解析到next之前减少所有JS Promises
- 为什么javascript ES6 Promises在解析后继续执行
- 控制Promises队列
- 副作用/传递到函数中的全局变容变化
- 有没有可能以某种方式用Promises运行同步循环
- ES6 Promises in Mocha
- ES6-Promises在使用Node MySQL时出现故障
- 使用TypeScript和Promises异步加载/卸载内容
- Promises是调用`.then`后执行副作用所需的A+Promises吗