我已经开发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表示异步操作的未来结果。当然,按照你的方式来写,收效甚微。但是如果你按照它们应该被使用的方式来编写它们,你可以用一种类似于同步代码的方式来编写异步代码,并且更容易遵循:

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

当然,代码并没有减少多少,但是可读性大大提高了。

但这还没有结束。让我们来看看真正的好处:如果您想在任何步骤中检查任何错误,该怎么办?如果是回调就太糟糕了,但如果是承诺,那简直就是小菜一碟:

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

几乎和尝试{…} 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个对api、api2、api3的调用可以同时运行(例如,如果它们是AJAX调用),但你需要等待这3个调用,那该怎么办?如果没有承诺,你就必须创造出某种反击。有了承诺,使用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.
});

希望你现在能从新的角度看待承诺。

其他回答

不,一点也不。

回调函数是JavaScript中的函数,在另一个函数执行完成后,将被调用并执行。那么它是如何发生的呢?

实际上,在JavaScript中,函数本身被视为对象,因此也被视为所有其他对象,甚至函数也可以作为参数发送给其他函数。人们能想到的最常见和最通用的用例是JavaScript中的setTimeout()函数。

承诺只是一种处理和构造异步代码的临时方法,而不是用回调来做同样的事情。

Promise在构造函数中接收两个回调:resolve和reject。承诺中的这些回调为我们提供了对错误处理和成功案例的细粒度控制。当promise执行成功时使用resolve回调,而reject回调用于处理错误情况。

除了上面这些精彩的答案,还可以再加2分:

1. 语义的差异:

应许可能在创世之时就已经解决了。这意味着他们保证条件,而不是事件。如果它们已被解析,则传递给它的已解析函数仍将被调用。

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

2. 控制反转

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

有关解释请参考Javascript事件循环。

对于promise,控制驻留在调用程序中。如果存储promise对象,.then()方法可以在任何时候调用。

JavaScript的Promise实际上使用回调函数来确定Promise被解析或拒绝后要做什么,因此两者并没有本质上的不同。Promises背后的主要思想是采用回调——特别是在您想要执行某种操作的地方嵌套回调,但它将更易于阅读。

承诺概述:

在JS中,我们可以将异步操作(例如数据库调用,AJAX调用)包装在承诺中。通常,我们希望在检索到的数据上运行一些额外的逻辑。JS承诺有处理异步操作结果的处理程序函数。处理程序函数甚至可以在其中包含其他异步操作,这些操作可能依赖于前面的异步操作的值。

一个承诺总是有以下三种状态:

待定:每个承诺的起始状态,既未完成也未拒绝。 完成的:操作成功完成。 rejected:操作失败。

挂起的承诺可以用值来解决/实现或拒绝。然后调用以下将回调作为参数的处理程序方法:

promise .prototype.then():当promise被解析时,该函数的回调参数将被调用。 promise .prototype.catch():当promise被拒绝时,这个函数的回调参数将被调用。

虽然上面的方法技能获得回调参数,但它们远比使用要好 这里只有回调的例子可以说明很多问题:

例子

function createProm(resolveVal, rejectVal) { return new Promise((resolve, reject) => { setTimeout(() => { if (Math.random() > 0.5) { console.log("Resolved"); resolve(resolveVal); } else { console.log("Rejected"); reject(rejectVal); } }, 1000); }); } createProm(1, 2) .then((resVal) => { console.log(resVal); return resVal + 1; }) .then((resVal) => { console.log(resVal); return resVal + 2; }) .catch((rejectVal) => { console.log(rejectVal); return rejectVal + 1; }) .then((resVal) => { console.log(resVal); }) .finally(() => { console.log("Promise done"); });

The createProm function creates a promises which is resolved or rejected based on a random Nr after 1 second If the promise is resolved the first then method is called and the resolved value is passed in as an argument of the callback If the promise is rejected the first catch method is called and the rejected value is passed in as an argument The catch and then methods return promises that's why we can chain them. They wrap any returned value in Promise.resolve and any thrown value (using the throw keyword) in Promise.reject. So any value returned is transformed into a promise and on this promise we can again call a handler function. Promise chains give us more fine tuned control and better overview than nested callbacks. For example the catch method handles all the errors which have occurred before the catch handler.

承诺不是回调。promise表示异步操作的未来结果。当然,按照你的方式来写,收效甚微。但是如果你按照它们应该被使用的方式来编写它们,你可以用一种类似于同步代码的方式来编写异步代码,并且更容易遵循:

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

当然,代码并没有减少多少,但是可读性大大提高了。

但这还没有结束。让我们来看看真正的好处:如果您想在任何步骤中检查任何错误,该怎么办?如果是回调就太糟糕了,但如果是承诺,那简直就是小菜一碟:

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

几乎和尝试{…} 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个对api、api2、api3的调用可以同时运行(例如,如果它们是AJAX调用),但你需要等待这3个调用,那该怎么办?如果没有承诺,你就必须创造出某种反击。有了承诺,使用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.
});

希望你现在能从新的角度看待承诺。