在你致电.then
之前,我Knex API for building a schema实际创建一张桌子的方式让我感到兴奋。
例如,此代码实际上不会影响数据库:
knex.schema.createTable('users', table => {
table.string('name')
})
但是这段代码会:
knex.schema.createTable('users', table => {
table.string('name')
}).then(console.log.bind(console))
这种行为(在调用.then
之前没有做任何事情):
c)未指明
我阅读了规范,似乎行为未指定,但我不确定。这似乎太重要了,不能指明。
请参阅@ Vohuman的回答:Knex架构构建器上的then
方法首先执行副作用,然后返回一个promise。因此,即使我的问题的答案是(b),Knex也不会违反规范。虽然在这种情况下选择then
作为方法名称是非常误导的。
答案 0 :(得分:2)
这种行为是错误的;调用then()
不应该超出promise本身的任何副作用(即执行回调)。
然而,该规范实际上并没有说明这一点。
答案 1 :(得分:2)
这并非完全“错误”,尽管并不常见。 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,专门用于即时与批量查询:
当您创建一个旨在将其添加到批处理中的请求时,请不要在将请求添加到批处理之后调用其
then
方法。如果在添加请求之前调用then
方法,则会立即发送请求,而不是作为批处理的一部分。
正如SLaks指出的那样,在文档中的任何地方都没有明确指定:为了使对象符合Promises/A+,它必须有一个名为then
的方法。语义和返回值,没有任何内容指定then
不能有其他行为。当然,这会禁止这些API库将then
方法重命名为更合适的方法,例如thenIssueRequest
或thenGetResponse
。 (您可以添加别名,但必须存在then
。)
作为一名API设计师,唯一的选择是将承诺的创建与then
的链接分开,但需要注意的是几乎每次调用then
都会有额外的方法调用先于或包裹它。因为then
是访问结果的唯一方法,所以我可以理解如何优化常见情况会导致删除额外的方法。
fluentApi.createRequest().parameterA(1).parameterB(2).issue().then(...);
// or
fluentApi.issue(fluentApi.createRequest().parameterA(1).parameterB(2)).then(...);
最后,请记住,您应该始终catch
承诺,这会触发请求:
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();
答案 2 :(得分:1)
knex
是一个查询构建器。 then
只是一个辅助函数,它执行生成的[SQL]语句并在后台调用promise对象的then
函数。如果用then
函数替换.toString
,您将获得生成的字符串。 then
这里不是promise对象的方法。
来自knex
源代码:
Target.prototype.then = function(/* onFulfilled, onRejected */) {
const result = this.client.runner(this).run()
return result.then.apply(result, arguments);
};