不只承诺回调吗?

我已经开发JavaScript几年了,我完全不了解关于promise的麻烦。

看来我所做的就是改变:

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

哪个代码更多,可读性更差。我在这里什么都没得到,也不是突然变得神奇地“平坦”。更不用说必须将事情变成诺言。

那么,这里的诺言有什么大惊小怪的呢?

阿飞阳光2020/03/16 15:15:30

JavaScript Promises实际上使用回调函数来确定在Promise被解决或拒绝后该怎么做,因此两者没有本质上的不同。Promises背后的主要思想是采用回调-尤其是嵌套的回调,您想在其中执行某种操作,但它更具可读性。

JinJin梅2020/03/16 15:15:30

一点都不。

Callbacks are simply Functions In JavaScript which are to be called and then executed after the execution of another function has finished. So how it happens?

Actually, In JavaScript, functions are itself considered as objects and hence as all other objects, even functions can be sent as arguments to other functions. The most common and generic use case one can think of is setTimeout() function in JavaScript.

Promises are nothing but a much more improvised approach of handling and structuring asynchronous code in comparison to doing the same with callbacks.

Promise在构造函数中收到两个回调:解析和拒绝。promise中的这些回调为我们提供了对错误处理和成功案例的细粒度控制。当成功执行Promise时,将使用resolve回调,并使用reject回调来处理错误情况。

JimHarry2020/03/16 15:15:30

承诺不是回调,它们都是促进异步编程的编程习惯用法。使用使用协程或生成器返回promise的异步/等待方式编程可以被认为是第三个这样的习惯用法。这些习惯用法在不同编程语言(包括Javascript)中的比较在这里:https : //github.com/KjellSchubert/promise-future-task

逆天宝儿米亚2020/03/16 15:15:30

承诺不是回调。许诺代表异步操作未来结果当然,以您的方式编写它们,您会获得很少的收益。但是,如果按照使用它们的方式来编写它们,则可以以类似于同步代码的方式编写异步代码,并且更容易遵循:

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

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

但这还不是终点。让我们发现真正的好处:如果您想检查任何步骤中的任何错误怎么办?用回调来做到这一点将是一件令人头疼的事,但是用promise却是小菜一碟:

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

And even better: What if those 3 calls to api, api2, api3 could run simultaneously (e.g. if they were AJAX calls) but you needed to wait for the three? Without promises, you should have to create some sort of counter. With promises, using the ES6 notation, is another piece of cake and pretty neat:

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

Hope you see Promises in a new light now.

宝儿猴子2020/03/16 15:15:30

除了上述真棒答案外,还可以添加2点:

1.语义差异:

创建时可能已经解决了承诺。这意味着它们保证条件而不是事件如果它们已经解决,则传递给它的已解决函数仍将被调用。

相反,回调处理事件。因此,如果您感兴趣的事件发生在注册回调之前,则不会调用该回调。

2.控制权倒置

回调涉及控制反转。当您使用任何API注册回调函数时,JavaScript运行时都会存储该回调函数,并在准备好运行时从事件循环中调用它。

请参阅Javascript事件循环以获取解释。

通过Promises,控制权归调用程序所有。如果我们存储promise对象,则可以随时调用.then()方法

Harry神乐2020/03/16 15:15:30

除了其他答案,ES2015语法与promises无缝融合,从而减少了更多样板代码:

// Sequentially:
api1()
  .then(r1 => api2(r1))
  .then(r2 => api3(r2))
  .then(r3 => {
      // Done
  });

// Parallel:
Promise.all([
    api1(),
    api2(),
    api3()
]).then(([r1, r2, r3]) => {
    // Done
});
西里达蒙2020/03/16 15:15:30

除了已经确定的答案,用ES6箭头功能承诺把从适度闪耀小蓝矮成一颗红巨星。那即将崩溃成超新星:

api().then(result => api2()).then(result2 => api3()).then(result3 => console.log(result3))

正如oligofren所指出的,在api调用之间没有参数的情况下,您根本不需要匿名包装函数:

api().then(api2).then(api3).then(r3 => console.log(r3))

最后,如果您想达到超大质量的黑洞水平,可以等待Promises:

async function callApis() {
    let api1Result = await api();
    let api2Result = await api2(api1Result);
    let api3Result = await api3(api2Result);

    return api3Result;
}