【问题标题】:Improved way to deal with callbacks inside promises改进了在 Promise 中处理回调的方法
【发布时间】:2019-02-08 00:46:37
【问题描述】:

我有以下代码在promises 内使用callbacks

const clue = 'someValue';

const myFunction = (someParam, callback) => {
    someAsyncOperation(someParam) // this function returns an array
    .then((array) => {
        if (array.includes(clue)){
            callback(null, array); // Callback with 'Success'
        }
        else{
            callback(`The array does not includes: ${clue}`); // Callback with Error
        }
    })
    .catch((err) => {
        // handle error
        callback(`Some error inside the promise chain: ${err}`) // Callback with Error
    })
}

然后这样称呼它:

myFunction (someParam, (error, response) => {
    if(error) {
        console.log(error);
    }
    else {
        // do something with the 'response'
    }    
})

阅读了一些文档,我发现有一些改进的方法可以做到这一点:

const myFunction = (someParam, callback) => {
    someAsyncOperation(someParam) // this function returns an array
    .then((array) => {
        if (array.includes(clue)){
            callback(array);
        }
        else{
            callback(`The array does not includes: ${clue}`);
        }
    }, (e) => {
        callback(`Some error happened inside the promise chain: ${e}`);
    })
    .catch((err) => {
        // handle error
        callback(`Some error happened with callbacks: ${err}`)
    })
}

我的问题:

就性能或最佳实践而言,可以在 Promise 中调用 'callback' function,因为这两种方式都表明,或者我做错了什么,我的意思是一些 Promise 反模式方式?

【问题讨论】:

  • 很确定您不应该有 both 错误处理程序(作为.then 的第二个参数) catch。最好只有一个catch
  • 另请注意,您的第二个代码在成功期间调用callback 并使用array 作为第一个 参数(error)而不是第二个参数( response)。
  • 不要在 Promise 中使用回调——这是一种反模式。只需返回一个 Promise 并让 Promise 处理完成或错误的通知。这就是它们的设计目的。然后,调用者将在返回的 Promise 上使用 .then().catch() 而不是回调。这是 Javascript 的现状和未来。
  • 不要不承诺
  • @robe007 - 根据您的要求,我添加了一个答案来说明。

标签: javascript callback promise es6-promise asynccallback


【解决方案1】:

这似乎真的倒退了,并剥夺了 promise 管理错误并将其传递到链下的好处

从函数返回异步承诺,不要用回调中断它。然后在链的末端添加一个catch

const myFunction = (someParam) => {
  // return the promise
  return someAsyncOperation(someParam) // this function returns an array
    .then((array) => {
      return array.includes(clue) ? array : [];
    });
}

myFunction(someParam).then(res=>{
  if(res.length){
     // do something with array
  }else{
     // no results
  }
}).catch(err=>console.log('Something went wrong in chain above this'))

【讨论】:

  • 这个答案和jfriend00's 答案很好解释,但我选择这个是因为是第一个。可以说今天又学到了!
【解决方案2】:

不要在 Promise 内部使用回调,这是一种反模式。一旦你已经有了 Promise,就使用它们。不要“不承诺”将它们变成回调 - 这是代码结构的倒退。相反,只需返回承诺,然后您就可以使用 .then() 处理程序来设置您想要的解析值或抛出错误来设置您想要的拒绝原因:

const clue = 'someValue';

const myFunction = (someParam) => {
    return someAsyncOperation(someParam).then(array => {
        if (!array.includes(clue)){
            // reject promise
            throw new Error(`The array does not include: ${clue}`);
        }
        return array;
    });
}

然后,调用者会这样做:

myFunction(someData).then(array => {
    // success
    console.log(array);
}).catch(err => {
    // handle error here which could be either your custom error
    // or an error from someAsyncOperation()
    console.log(err);
});

这为您提供了一个优势,即调用者可以使用 Promise 的所有功能将此异步操作与任何其他操作同步,轻松将错误全部传播到一个错误处理程序,使用 await 等...

【讨论】:

  • 也可以在someAsyncOperation 中添加catch 语句对吗?
  • @robe007 - 是的,但没有必要,除非您想在本地“处理”该错误并且不让调用者直接看到该错误。如果someAsyncOperation() 被拒绝,那么您的.then() 将不会被调用,调用者将直接看到被拒绝的承诺,而他们自己已经需要拥有的.catch() 将看到错误。
猜你喜欢
  • 1970-01-01
  • 2014-11-12
  • 2019-05-17
  • 2017-11-20
  • 1970-01-01
  • 1970-01-01
  • 2018-05-10
  • 1970-01-01
  • 2016-03-26
相关资源
最近更新 更多