为什么此代码段的语句的执行顺序会根据承诺的拒绝/解决方案而改变?

时间:2019-01-25 23:15:19

标签: javascript node.js es6-promise

请考虑以下代码段:

var xmldoc = new XmlDocument();
xmldoc.LoadXml(x);
var r = xmlDoc.SelectNodes("//X/C | //X/A");

foreach (XmlNode i in r)
    Debug.WriteLine(i.Value);

其执行将产生以下输出:

function func1() {
  return Promise.resolve();
}

function func2() {
  func1()
    .then(res => console.log("In func2 'then'"))
    .catch(err => console.log("In func2 'catch"));
}

function func3() {
  Promise.resolve()
    .then(() => {
      func2();
    })
    .then(() => {
      console.log("In func3 'then'");
    });
}

func3();

如果将In func2 'then' In func3 'then' 的返回值替换为func1,如下所示:

Promise.reject()

,promise的回调将以不同的顺序执行,从而产生:

function func1() {
  return Promise.reject();
}

function func2() {
  func1()
    .then(res => console.log("In func2 'then'"))
    .catch(err => console.log("In func2 'catch"));
}

function func3() {
  Promise.resolve()
    .then(() => {
      func2();
    })
    .then(() => {
      console.log("In func3 'then'");
    });
}

func3();

这是在节点和镶边中观察到的输出顺序。

这是怎么回事?为什么In func3 'then' In func2 'catch 的'catch'与'then'具有不同的执行优先级?

该代码段很奇怪,但我想知道为什么会发生这种行为-是某些实施细节的附带影响,还是一般调度策略的说明?

1 个答案:

答案 0 :(得分:1)

func3中初始化的承诺链实际上并未与在func2中初始化的承诺链连接;与您的

.then(() => {
  func2();
})

由于未返回func2的结果,因此func2的承诺未连接到func3中的链。您所看到的时间可以归结为毫秒级的时间:如果一个Promise解析(或拒绝),而另一个未与它链接的Promise 基本上同时解析(或拒绝),则该链的{{1 }}或.then首先运行?这不是直观的,也不是您的代码应依赖的逻辑。

如果在使用.catch时在.then中切换.catchfunc2,您将看到与第二个代码相同的行为- Promise.resolve日志在func3日志之前运行。

func2

最佳解决方案:永远不依赖微秒计时,而是始终通过function func1() { return Promise.resolve(); } function func2() { func1() .catch(err => console.log("In func2 'catch")) .then(res => console.log("In func2 'then'")) } function func3() { Promise.resolve() .then(() => { func2(); }) .then(() => { console.log("In func3 'then'"); }); } func3();链接您的Promises(无论您是处于return之类的独立函数中,还是处于{{1}内部) }),因此一切都链接在一起,事情将完全可预测:

func2

现在,很明显.then的链将始终完全完成,然后再移至function func1() { return Promise.reject(); } function func2() { // return the chain: return func1() .then(res => console.log("In func2 'then'")) .catch(err => console.log("In func2 'catch")); } function func3() { // return the chain (just in case consumers of func3 want to use the chain): return Promise.resolve() .then(() => { // return the chain: return func2(); }) .then(() => { console.log("In func3 'then'"); }); } func3();(无论是否有错误),因为func2链是在In func3 'then'的{​​{1}}内部返回。