我怎样才能像传统的 'return' 语句一样绕过承诺链中的其余“then”?

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

我将离开我的同步、多线程 Java 编程世界,拥抱单线程、异步、基于 promise 的 ES6 JavaScript 世界。我不得不理解将以同步方式编写的函数映射到基于 promise 的异步函数的概念。我目前正在混合使用 ES6 原生 Promises 和 bluebird promises。

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

同步函数

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

基于异步 Promise 的 equivlanet

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

现在这是我的问题:是否有一种干净的(即内置的,已经想到的)方法来模拟同步 return 绕过其余部分的想法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;
}

(我的猜测)基于异步 Promise 的等价物

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;
    });
}

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

我知道这些备选方案,所以也许我可以判断其中任何一个是否真的是正确的方法:

你在谈论承诺链中的条件流,其中早期 return 是一种有用的风格。

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

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(...) 必须结束承诺链的所有其他用户 在函数之外,使链最终无法使用。

使用这种分支方法,我所追求的传统 return 行为就完成了,因为函数结束前链中的最后一个 then 是链将在其执行时拾取的地方return 值在函数外部使用——在这种情况下,如果 var4.validfalse,则在 return var3; 之后,否则在 return var5; 之后。