在异步编程概念已经普及的今天,我们依然要谈一谈它,对于我们做前端代码的意义。当你通过Ajax请求数据使用回调函数来获取数据时,这就是一种异步编程。
$.ajax({
url: 'xxx',
success: function(data){
// data
}
})
考虑到JavaScript属于单线程的特点,异步对于这门语言就可见多么的重要。你可以试着想想,当我们没有异步时,我正准备提交一个信息,界面就卡住了,一直要等待信息返回结果才能有接下来的其他操作,这很痛苦。在JavaScript的世界里,异步是非常重要的一件事情。
Promise正是想来处理这样的异步编程,如果我们用Promise该如何处理这段Ajax?
function fetch(){
return new Promise(function(resolve,reject){
$.ajax({
url: 'xxx',
success:function(data){
resolve(data)
},
error:function(error){
reject(error)
}
})
})
}
fetch().then(function(data){
}).catch(function(error){})
这辅助我们避免了回调地狱式的恐惧,更优雅的处理了回调。如果,你有兴趣,可以配合着 Promise 来学习【理论上的内容,可以仔细阅读】。
Promise声明周期
- 进行中(pending)
- 已经完成(fulfilled)
- 拒绝(rejected)
如同上面Ajax的例子,我们可以很好的包装一个函数,让fetch函数返回一个Promise对象。在Promise构造函数里,可以传入一个callback,并且在这里完成主体逻辑的编写。唯一需要注意的是:Promise对象只能通过resolve和reject函数来返回,在外部使用then或catch来获取。如果你直接抛出一个错误(throw new Error('error')),catch也是可以正确的捕获到的。
Promise其他的方法
- Promise.all(当所有在可迭代参数中的 promises 已完成,或者第一个传递的 promise(指 reject)失败时,返回 promise。)
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "foo");
});
Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
});
- Promise.race(返回一个新的 promise,参数iterable中只要有一个promise对象"完成(resolve)"或"失败(reject)",新的promise就会立刻"完成(resolve)"或者"失败(reject)",并获得之前那个promise对象的返回值或者错误原因。)
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// 两个都完成,但 p2 更快
});
有趣的是如果你使用ES6的class,你是可以去派生Promise的,就像我们想派生Array一样:
class MePromise extends Promise{
// 处理 ...
}
那么,除了Promise还有没有更牛逼的方案?这是有的,目前的异步编程已经从最初的callback进化到了如下的顺序。
callback -> Promise -> generator -> async await
未来,肯定属于async await了。