异步函数执行顺序

时间:2019-07-24 20:46:45

标签: javascript node.js

我有一个异步函数,其编写方式如下:

pool.query(`select id from table1`)
  .then(rows=>{
    pool.query(`selectQuery1`)
      .then(rows=>{
        return pool.query(`selectQuery2`)
      })
    .then(rows=>{
      console.log('First')
      return pool.query(`selectQuery3`)
    })
  })
  .then(rows=>{
    console.log('Second')
    return pool.query(`selectQuery4`)
  })

我当时以为最后一个.then应该在其他所有功能之后触发。但是console.log显示

second
first 

我不明白为什么会这样

2 个答案:

答案 0 :(得分:2)

您没有将它们全部链接到一个顺序的链中。

您创建了两个平行且独立的链条,所以这只是一场比赛,它首先完成。

在第二个return前面添加一个pool.query(),事情将会像这样改变:

pool.query(`select id from table1`)
  .then(rows=>{
    // **** add return here ****
    return pool.query(`selectQuery1`)
      .then(rows=>{
        return pool.query(`selectQuery2`)
      })
    .then(rows=>{
      console.log('First')
      return pool.query(`selectQuery3`)
    })
  })
  .then(rows=>{
    console.log('Second')
    return pool.query(`selectQuery4`)
  });

通过省略return,您创建了一个独立于父链的完整独立的诺言链,因此这只是一场竞赛,看看哪一个先完成,以便最终取决于完成的速度这两个链中的各种操作,并且每次运行时的完成顺序甚至可能都不相同。

仅供参考,如果您确实想要顺序操作,那么通常最好将您的链条扁平化为:

fn().then(...).then(...).then(...).then(...)

不是:

fn1().then(function() {
    return fn2(...).then(...).then(...)
}).then(...)

因为前者要清楚得多,所以您要尝试做的事情。如果您有逻辑分支(未显示),则有时会被迫离开平面设计。

展平后的代码如下:

pool.query(`select id from table1`).then(rows=>{
    return pool.query(`selectQuery1`);
}).then(rows => {
    return pool.query(`selectQuery2`);    
}).then(rows => {
    return pool.query(`selectQuery3`);
}).then(rows => {
    return pool.query(`selectQuery4`);
}).then(rows => {
    console.log("done");
}).catch(err => {
    console.log(err);
});

或者,使用异步/等待,它甚至可能更干净:

try {
    let rows1 = await pool.query(`select id from table1`);
    let rows2 = await pool.query(`selectQuery1`);
    let rows2 = await pool.query(`selectQuery2`);
    let rows3 = await pool.query(`selectQuery3`);
    let rows4 = await pool.query(`selectQuery4`);
    console.log("done");
} catch(e) {
    console.log(err);
}

仅供参考,无法从.then()处理程序内部返回承诺链几乎总是一个错误,因为无法与外界交流成功或失败的方法。

我所见过的唯一正确决​​策是发生火灾并忘记操作,例如关闭文件,如果操作失败,您别无所求,而您希望其余操作能够正常进行,不等待完成。但这是罕见的例外,而不是规则。

答案 1 :(得分:0)

正如其他人所述,技术问题是您缺少退货声明。但是,您还使用了非凝缩式缩进样式,这会使意图不那么清晰,并且更难以发现错误。

这是您的代码,其中添加了一些换行符和缩进更改。这个想法是,a)链式方法调用应该始终是多行的,每条链都在相同的层次上; b)使用块的箭头函数应该总是缩进一个比其存在范围高一个层次。 >

pool
    .query(`select id from table1`)
    .then(rows => {
        // FIX: add return
        pool
            .query(`selectQuery1`)
            .then(rows => {
                return pool.query(`selectQuery2`);
            })
            .then(rows => {
                console.log('First');
                return pool.query(`selectQuery3`);
            });
    })
    .then(rows => {
        console.log('Second');
        return pool.query(`selectQuery4`);
    });

以这种方式显示时,很容易发现pool有一种内部用法,而它前面没有return