是的,promise是异步回调。它们不能做回调所不能做的任何事情,并且在异步中您面临与普通回调相同的问题。
然而,承诺不仅仅是回调。它们是一种非常强大的抽象,允许更清晰、更好的功能代码和更少容易出错的样板文件。
那么主要思想是什么呢?
承诺是表示单个(异步)计算结果的对象。他们只决心达到那个结果一次。这意味着几件事:
promise实现了一个观察者模式:
You don't need to know the callbacks that will use the value before the task completes.
Instead of expecting callbacks as arguments to your functions, you can easily return a Promise object
The promise will store the value, and you can transparently add a callback whenever you want. It will be called when the result is available. "Transparency" implies that when you have a promise and add a callback to it, it doesn't make a difference to your code whether the result has arrived yet - the API and contracts are the same, simplifying caching/memoisation a lot.
You can add multiple callbacks easily
承诺是可链的(如果你愿意,可以是单链的):
If you need to transform the value that a promise represents, you map a transform function over the promise and get back a new promise that represents the transformed result. You cannot synchronously get the value to use it somehow, but you can easily lift the transformation in the promise context. No boilerplate callbacks.
If you want to chain two asynchronous tasks, you can use the .then() method. It will take a callback to be called with the first result, and returns a promise for the result of the promise that the callback returns.
听起来复杂吗?接下来是代码示例。
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库。
承诺有什么好大惊小怪的?
Promise抽象允许更好的函数组合。例如,在链接之后,all函数为多个并行等待的承诺的组合结果创建一个承诺。
最后但并非最不重要的承诺带有集成的错误处理。计算的结果可能是承诺用一个值来实现,或者用一个理由来拒绝。所有的复合函数都自动处理这个问题,并在承诺链中传播错误,因此您不需要在任何地方显式地关心它——与普通回调实现相反。最后,您可以为所有发生的异常添加一个专用的错误回调。
更不用说把事情变成承诺了。
这是相当微不足道的,实际上与良好的承诺库,看看我如何转换现有的回调API承诺?