如何绕过'那么's在承诺链中,就像传统的'return'陈述

How can I bypass the rest of the 'then's in a promise chain, like a traditional 'return' statement?

本文关键字:传统 return 陈述 承诺 那么 何绕过      更新时间:2024-01-20

我将放弃我的同步、多线程Java编程世界,拥抱ES6 JavaScript的单线程、异步、基于承诺的世界。我不得不抓住这个概念,将以同步风格编写的函数映射到基于异步promise的函数。我目前使用的是ES6原生承诺和蓝鸟承诺的混合。

我将从一个例子开始为我的问题做准备(Java中的同步例子,ES6中的异步例子):

同步功能

private Object doSomething(Object var1, Object var2) {
    Object var3 = blockingFunction(var1);
    Object var4 = anotherBlockingFunction(var2, var3);
    return var4;
}

基于异步Promise的equivalanet

function doSomething(var1, var2) {
    return asyncFunction(var1)
    .then(var3 => {
        return anotherAsyncFunction(var2, var3);
    })
    .then(var4 => {
        return var4;
    });
}

现在我的问题是:是否有一种干净的(即内置的、已经考虑过的)方法来模拟同步return的想法,以绕过返回链的其余部分?

为了解释,这里还有两个同步和异步的例子:

同步功能

private Object doSomething(Object var1, Object var2) {
    Object var3 = blockingFunction(var1);
    Object var4 = anotherBlockingFunction(var2, var3);
    if (!var4.isValid()) {
        return var3;
    }
    // If var4.isValid() equates to false, we bypass the following statements
    // and return the value of var3 as the final value
    Object var5 = var4.validateObject();
    var5.setSomething(var1);
    return var5;
}

(我的猜测是)基于异步承诺的等价物

function doSomething(var1, var2) {
    // Predefine variables within this block so they persist between 'then's
    let var3;
    let var4;
    let var5;
    let bypassCondition;
    return asyncFunction(var1)
    .then(result => {
        var3 = result;
        return anotherAsyncFunction(var2, var3);
    })
    .then(result => {
        var4 = result;
        bypassCondition = !var4.valid;
        if(bypassCondition) {
            return var3;
        }
    })
    .endChain(bypassCondition)
    // If the bypassCondition is true, the entire chain would return the value
    // of the previous then's return;
    // Otherwise, if false, the chain continues
    .then(() => {
        return var4.validateObject();
    })
    .then(result => {
        var5 = result;
        var5.something = var1;
        return var5;
    });
}

这样的东西已经存在了吗?

我知道这些替代方案,所以也许我可以判断两者是否真的是正确的方法:

  • 在链的中间抛出一个异常,并在最后捕获它,以便绕过其他语句
  • 将每个后续的then的函数封装在if (!bypassCondition)块中,这样它们就不会全部执行

您正在讨论promise链中的条件流,其中早期返回是一种有用的风格。

是的,这是可能的,通过有条件地分支你的链。注意括号:

function doSomething(var1, var2) {
  return asyncFunction(var1)
  .then(var3 => anotherAsyncFunction(var2, var3))
  .then(var4 => (!var4.isValid())? var3 : var4.validateObject()
    .then(var5 => (var5.something = var1, var5)));
}

注意最后一行的缩进,其中.thenvar4.validateObject()不匹配。

这很好地映射到ES7(在那里我们可以提前进行引导):

async function doSomething(var1, var2) {
  let var3 = await asyncFunction(var1);
  let var4 = await anotherAsyncFunction(var2, var3);
  if (!var4.isValid()) {
    return var3;
  }
  let var5 = await var4.validateObject();
  var5.something = var1;
  return var5;
}

(您没有指定validateObject是否是异步的,所以我选择了异步)。

这里的这个答案是我获得这个问题答案的地方。

正如Bergi所指出的,我在这里所做的是分支。我所需要做的就是将继续的分支放在的else块中,如下所示:

function doSomething(var1, var2) {
    // Predefine variables within this block so they persist between 'then's
    let var3;
    let var4;
    let var5;
    return asyncFunction(var1)
    .then(result => {
        var3 = result;
        return anotherAsyncFunction(var2, var3);
    })
    .then(result => {
        var4 = result;
        if(!var4.valid) {
            return var3;
        }
        else {
            return Promise.resolve()
            .then(() => {
                return var4.validateObject();
             })
             .then(result => {
                var5 = result;
                var5.something = var1;
                return var5;
             });
        })
    }
}

从根本上讲,你不能停止承诺链。尽管看起来我应该能够,但请记住,其他函数会将.then(...)附加到函数的输出中。该代码没有区分then语句是出现在一个函数内还是出现在函数外,因此我提出的.endchain(...)将不得不终止函数外的promise链的所有其他用户,从而使该链最终不可用。

使用这种分支方法,我所追求的传统return行为得以实现,因为函数结束前链中的最后一个then是在函数外使用其返回值时链将拾取的位置—在这种情况下,如果var4.validfalse,则在return var3;之后,否则在return var5;之后。