promise 不就是回调吗?

新手上路,请多包涵

我已经开发 JavaScript 几年了,我根本不理解关于承诺的大惊小怪。

似乎我所做的就是改变:

 api(function(result){
    api2(function(result2){
        api3(function(result3){
             // do work
        });
    });
});

无论如何我都可以使用像 async 这样的库,比如:

 api().then(function(result){
     api2().then(function(result2){
          api3().then(function(result3){
               // do work
          });
     });
});

哪个代码更多,可读性更差。我在这里没有得到任何东西,它也不是突然神奇地“平坦”。更不用说必须将事情转换为承诺。

那么,这里关于 promise 的大惊小怪是什么?

原文由 Benjamin Gruenbaum 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 296
2 个回答

承诺不是回调。承诺代表 异步操作的未来结果。当然,按照你的方式编写它们,你得不到什么好处。但是如果你按照它们的使用方式编写它们,你可以用一种类似于同步代码的方式编写异步代码,并且更容易理解:

 api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
});

当然,代码不会少很多,但可读性会更高。

但这还没有结束。让我们发现真正的好处:如果您想检查任何步骤中的错误怎么办?用回调来做这件事会很糟糕,但是用 promises 是小菜一碟:

 api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
});

try { ... } catch 块几乎相同。

更好的是:

 api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
}).then(function() {
     //do something whether there was an error or not
     //like hiding an spinner if you were performing an AJAX request.
});

甚至更好:如果这 3 个调用 apiapi2api3 可以同时运行(例如,如果它们是 AJA 来等待你)他们三个?没有承诺,您应该必须创建某种计数器。有了 promises,使用 ES6 符号,又是小菜一碟,而且非常简洁:

 Promise.all([api(), api2(), api3()]).then(function(result) {
    //do work. result is an array contains the values of the three fulfilled promises.
}).catch(function(error) {
    //handle the error. At least one of the promises rejected.
});

希望你现在以新的眼光看待 Promises。

原文由 Oscar Paz 发布,翻译遵循 CC BY-SA 3.0 许可协议

是的,Promises 是异步回调。他们不能做任何回调不能做的事情,而且你面临着与普通回调一样的异步问题。

然而,Promises 不仅仅是 回调。它们是一个非常强大的抽象,允许更清晰、更好的功能代码和不易出错的样板。

那么主要思想是什么?

Promises 是表示单个(异步)计算结果的对象。他们只 对那个结果下定 决心 一次。这意味着一些事情:

Promises 实现了观察者模式:

  • 在任务完成之前,您不需要知道将使用该值的回调。
  • 您可以轻松地 return 一个 Promise 对象,而不是期望回调作为函数的参数
  • Promise 将存储值,您可以随时 透明地 添加回调。当结果可用时将调用它。 “透明”意味着当你有一个承诺并向它添加一个回调时,结果是否已经到达对你的代码没有影响——API 和合同是相同的,大大简化了缓存/记忆。
  • 您可以轻松添加多个回调

Promises 是可链接的monadic如果你愿意 的话):

  • 如果您需要转换 promise 表示的值,您可以在 promise 上映射 一个转换函数并取回表示转换结果的新 promise。您无法以某种方式同步获取价值以使用它,但您可以轻松地在 promise 上下文中 提升 转换。没有样板回调。
  • 如果要链接两个异步任务,可以使用 .then() 方法。它将使用第一个结果调用回调,并返回回调返回的承诺结果的承诺。

听起来很复杂?代码示例的时间。

 var p1 = api1(); // returning a promise
var p3 = p1.then(function(api1Result) {
    var p2 = api2(); // returning a promise
    return p2; // The result of p2 …
}); // … becomes the result of p3

// So it does not make a difference whether you write
api1().then(function(api1Result) {
    return api2().then(console.log)
})
// or the flattened version
api1().then(function(api1Result) {
    return api2();
}).then(console.log)

扁平化并不是神奇的,但你可以轻松做到。对于你嵌套很重的例子,(近)等价物是

api1().then(api2).then(api3).then(/* do-work-callback */);

如果看到这些方法的代码有助于理解, 这里有几行最基本的承诺库

承诺有什么大惊小怪的?

Promise 抽象允许更好的函数可组合性。例如,在 then 旁边用于链接, all 函数为多个并行等待承诺的组合结果创建一个承诺。

最后但并非最不重要的一点是,Promises 带有集成的错误处理。计算的结果可能是 promise 得到 _满足_,或者被 _拒绝_。所有组合函数都会自动处理此问题并在承诺链中传播错误,因此您无需在任何地方明确关心它 - 与普通回调实现相反。最后,您可以为所有发生的异常添加一个专用的错误回调。

更不用说必须将事情转换为承诺。

这对于良好的 promise 库来说实际上是微不足道的,请参阅 如何将现有的回调 API 转换为 promises?

原文由 Bergi 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题