不承诺只是回调?
我几年来一直在开发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
});
});
});
这是更多的代码和更少的可读性。 我在这里没有获得任何东西,它也不是突然神奇地'平坦'。 更不用说必须将事物转换为承诺。
那么,这里承诺的大惊小怪是什么?
承诺不是回调。 承诺代表异步操作的未来结果 。 当然,按照你的方式写作,你没有什么好处。 但是,如果按照它们意图使用的方式编写它们,则可以使用类似于同步代码的方式编写异步代码,并且更容易遵循:
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
});
几乎与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次调用api
, api2
, api3
可以同时运行(例如,如果它们是AJAX调用),但是您需要等待三次? 没有承诺,你应该创建某种计数器。 承诺,使用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.
});
希望你现在看到承诺焕然一新。
是的,Promise是异步回调。 他们不能做任何回调无法做到的事情,而且你会遇到与普通回调相同的异步问题。
然而,Promise不仅仅是回调。 它们是一个非常强大的抽象,允许更干净,更好,功能强大的代码,而且容易出错的样板文件。
那么主要想法是什么?
Promise是代表单个(异步)计算结果的对象。 他们只解决了这个结果一次。 这意味着一些事情:
承诺实施观察员模式:
return
一个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 */);
如果看到这些方法的代码有助于理解,这里有几行中最基本的承诺lib。
什么是承诺的大惊小怪?
Promise抽象允许功能更好的组合性。 例如,旁边then
用于链接的all
功能创建多个并行的等待承诺的组合结果的承诺。
最后但并非最不重要的承诺带有集成的错误处理。 计算的结果可能是承诺是用价值来实现的,或者是有理由拒绝的。 所有的组合函数都会自动处理这个问题,并在promise链中传播错误,所以你不需要在任何地方明确地关心它 - 与简单的回调实现相反。 最后,您可以为所有发生的异常添加专用错误回调。
更不用说必须将事物转换为承诺。
实际上,对于良好的承诺库,这实际上是微不足道的,请参阅如何将现有的回调API转换为承诺?
除了Oscar和Bergi的真棒答案外,ES6的箭头功能Promises还是从一颗温和的小蓝星变成了一个红巨星。 即将崩溃成超新星:
api().then(result => api2()).then(result2 => api3()).then(result3 => console.log(result3))
链接地址: http://www.djcxy.com/p/1625.html