【问题标题】:How do you chain queries in order using knex.js?如何使用 knex.js 按顺序链接查询?
【发布时间】:2017-10-06 22:27:13
【问题描述】:

我在理解 Knex.js 中的 Promise 的工作原理时遇到了一些麻烦(使用 Bluebird.js 作为 Promise)。我正在尝试做一些非常简单的事情,依次执行不同的插入语句,但我无法让它工作。

这是我目前所拥有的代码,用于在 authentication_type 表上执行插入操作,然后在 user_table 上执行插入操作,然后在类别表上执行插入操作。

// Import database connection
var knex = require('./db-connection.js');

// Add a row to authentication_type table so that user's can be created
function add_authentication_type() {
    return knex('authentication_type')
    .insert({id: 1, name: 'Internal'})
}

// Add a 'default' user with nil uuid
// Anything added without a user must link back to this user
function add_default_user() {
    return knex('user_table')
    .insert({user_table_id: knex.raw('uuid_nil()'),
            authentication_type: 1,
            authentication_token: "default"})
}

// Add categories so that locations can be created
function add_categories() {
    return knex('category')
    .insert([
    {name: "Hospital",
    description: "Where people go to get healed"},
    {name: "Police Dept",
    description: "Where people go when there’s trouble"},
    {name: "Fire Dept",
    description: "Where all the fire trucks are"}])
}

// Run the functions in the necessary order to fit constraints
add_authentication_type()
.then(add_default_user()
    .then(add_categories()))

我需要这些插入以正确的顺序从上到下发生,这样我就不会违反数据库的约束。这就是我试图通过在每个调用的 .then() 部分中链接调用来对最后几行进行的操作。我认为这会使第一个查询发生,然后是第二个,然后是第三个,但情况似乎并非如此,因为我在运行此代码时遇到约束违规错误。

我一直在阅读 Knex 和 Bluebird 的页面,但我无法掌握它。使用 Knex 执行这种顺序查询的正确方法是什么?

【问题讨论】:

    标签: javascript node.js knex.js


    【解决方案1】:

    knex 查询构建器只返回一个承诺,所以这只是正确链接这些承诺的问题。

    TL;DR: 这样做:

    add_authentication_type()
      .then(add_default_user)
      .then(add_categories)
    

    承诺链

    让您的代码正常工作的关键是理解这四行代码做了不同的事情:

    // A
    .then(add_default_user)
    // B
    .then(() => add_default_user())
    // C
    .then(add_default_user())
    // D
    .then(() => add_default_user)
    

    then 将在前面的承诺解决后调用作为参数传递给它的任何函数。在A 中,它调用add_default_user,它返回一个promise。在B 中,它调用了整个函数,该函数本身返回了一个返回承诺的函数。在这两种情况中,then 调用一个最终返回承诺的函数,这就是您正确链接承诺的方式。

    C 将无法按预期工作,因为您没有将函数传递给then,而是函数调用的结果。因为 Promise 和回调一样是异步的,所以 this 返回 undefined 并立即调用该函数,而不是等待前一个 Promise 解决。

    D 不起作用,因为您传递给 then 的函数实际上并未调用 add_default_user

    拉平链条

    如果你不小心,你可能会得到功能性但不完全可读的代码(类似于回调地狱的“承诺地狱”)。

    foo()
      .then((fooResult) => bar(fooResult)
        .then((barResult)=> qux(barResult)
          .then((quxResult)=> baz(quxResult)
          )
        )
      )
    

    这可行,但不必要地混乱。如果传递给then 的函数返回一个promise,则第一个then 调用可以跟第二个调用。然后第一个中的承诺解析为的值将被传递给第二个中的函数。这意味着上述内容可以展平为:

    foo()
      .then((fooResult) => bar(fooResult))
      .then((barResult)=> qux(barResult))
      .then((quxResult)=> baz(quxResult))
    

    **PROTIP:**如果您对排队电话很感兴趣,您也可以使用Promise.resolve() 启动您的承诺链,如下所示:

    Promise.resolve()
      .then(() => knex('table1').del())
      .then(() => knex('table2').del())
      .then(() => knex('table3').del())
    

    【讨论】:

    • 只是为了澄清:在你给出的例子中,在 A 案例中是否有任何东西传递给 add_default_user 函数?如果该函数接受一个参数会发生什么?
    • 无论前面的 Promise 解析为什么,都会作为参数传递给 then 内的函数。所以在foo().then(bar) 中,假设 foo 返回一个 Promise,无论 Promise 解析为什么值,(比如说“Foo!”)然后作为第一个参数传递给bar。这就是为什么:foo().then(bar) == foo().then(fooResult => bar(fooResult))
    • 感谢您的洞察力。在此示例中,add_default_user 返回 Promise(knex),而不是 knex 操作的实际结果。如果add_categories 需要add_default_user 操作的结果,例如新增用户的count?如何将count 传递给下一个承诺。
    猜你喜欢
    • 2018-08-25
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    • 2011-09-22
    • 2013-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多