【问题标题】:Should synchronous code called by Promise .then create a new Promise应该由 Promise 调用同步代码。然后创建一个新的 Promise
【发布时间】:2019-04-15 00:21:33
【问题描述】:

我已经实现了一些代码,其中异步代码后面跟着一些同步函数。例如:

function processSomeAsyncData() {
  asyncFuncCall()
    .then(syncFunction)
    .catch(error);
}

如果我理解正确then 也是一个承诺。那么,我是否也应该在同步代码中创建一个 Promise?

function syncFunction() {
  const p = new Promise (function (resolve, reject) {
    //Do some sync stuff
    ...
    resolve(data);
  }
  return p;
}

如果没有必要,如果发生错误,你如何拒绝同步代码的承诺?

【问题讨论】:

    标签: javascript node.js es6-promise


    【解决方案1】:

    您不需要显式地创建一个新的 Promise。有一个更简单的方法。

    这个例子是人为设计的,因为它永远不会失败,但重点是你不必创建一个promise,也不必返回一个resolve(val)。

    function syncFunction() {
      var j = "hi"
      if(j){
        return j;
      }
      return new Error('i am an error');
    }
    

    这将起作用:

    asyncFunction()
      .then(syncFunction);
    

    但如果你反其道而行之:

    syncFunction()
      .then(asyncFunction);
    

    您必须将您的 syncFunction 定义为:

    function syncFunction() {
    
      var j = "hi"
      return new Promise((resolve, reject) => {
        if(j){
          return resolve(j);
        }
        return reject('error');
      })  
    }
    

    编辑:为了向所有非信徒证明,请在您的计算机上本地试一试此人。证明您有这些可用的选项。 :)

    var Promise = require('bluebird');
    
    
    function b(h) {
        if(h){
            return h;
        }
        return Promise.resolve('hello from b');
    }
    
    function a(z) {
        return new Promise((resolve, reject)=> {
            if(z){return resolve(z)};
            return resolve('hello from a');
        })
    }
    
    a().then(b).then(x => console.log(x)).catch(e => console.log(e));
    b().then(a).then(x => console.log(x)).catch(e => console.log(e));
    

    【讨论】:

    • 在您的第二个示例中,new Promise 不需要,应使用 Promise.resolvePromise.reject 函数。
    • 在您的第一段代码中,返回一个承诺或一个值肯定不允许之后与.then 链接。
    • 我正在我的计算机上进行本地快速测试以证明这一点。给我一秒钟。 :)
    • @nils 是的,从then 处理程序返回非承诺值是完全有效的。请参阅this“从 onFulfilled 或 onRejected 回调函数返回的值将自动包装在已解决的承诺中
    • 同步函数应该抛出错误,而不是返回被拒绝的承诺!无论如何,异常都会在.then 函数中转换为拒绝,因此永远不需要以这种方式容纳异步调用者。同步函数可以从同步代码中调用,并且应该同步失败。封装规则。
    【解决方案2】:

    没有。同步函数可以从同步代码中调用,并且应该总是同步失败!它们不需要以任何方式符合异步调用者。如果发生错误,只需抛出一个错误。试试看:

    var asyncFuncCall = () => Promise.resolve();
    
    function syncFunction() {
      throw new Error("Fail");
    }
    
    asyncFuncCall()
      .then(syncFunction)
      .catch(e => console.log("Caught: " + e.message));

    之所以有效,是因为传递给 .then 的函数抛出的异常被转换为拒绝它应该返回的承诺。

    此外,传递给.then 的函数返回的任何值都将转换为使用该值解析的承诺。调用该函数的承诺代码会处理这个问题。

    这让您可以毫无问题地混合同步和异步代码:

    asyncFuncCallOne()
      .then(() => {
        var x = syncFunction();
        return asyncFuncCallTwo(x);
      })
      .catch(e => console.log(e.message));
    

    【讨论】:

      【解决方案3】:

      这是可选的。

      如果您从 syncFunction 返回一个 Promise,那么您的原始 Promise 只有在新 Promise 解决后才会解决,并且新 Promise 返回的任何值都将传递给链中的下一个 then

      如果您返回一个非 Promise 值,它将被传递给链中的下一个 then

      要从syncFunction 内拒绝,只需抛出一个异常。

      【讨论】:

      • 如果syncFunction返回一个promise,它应该重命名为asyncFunction
      猜你喜欢
      • 1970-01-01
      • 2018-03-12
      • 2013-12-29
      • 2018-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-30
      • 1970-01-01
      相关资源
      最近更新 更多