什么是 Promise
Promise 是异步编程的一种解决方案,比传统的异步解决方案【回调函数】和【事件】更合理、更强大。现已被 ES6 纳入进规范中。
- Promise 操作只会处在 3 种状态的一种:未完成态(pending)、完成态(resolved) 和失败态(rejected);
- Promise 的状态只会出现从未完成态向完成态或失败态转化;
- Promise 的状态一旦转化,将不能被更改;
API
Promise.resolve(value)
类方法,该方法返回一个以 value 值解析后的 Promise 对象
- 如果这个值是个 thenable(即带有 then 方法),返回的 Promise 对象会“跟随”这个 thenable 的对象,采用它的最终状态(指 resolved/rejected/pending/settled)
- 如果传入的 value 本身就是 Promise 对象,则该对象作为 Promise.resolve 方法的返回值返回。
- 其他情况以该值为成功状态返回一个 Promise 对象。
上面是 resolve 方法的解释,传入不同类型的 value 值,返回结果也有区别。这个 API 比较重要,建议大家通过练习一些小例子,并且配合上面的解释来熟悉它。
如下几个小例子:
//如果传入的 value 本身就是 Promise 对象,则该对象作为 Promise.resolve 方法的返回值返回。
function fn(resolve){
setTimeout(function(){
resolve(123);
},3000);
}
let p0 = new Promise(fn);
let p1 = Promise.resolve(p0);
// 返回为true,返回的 Promise 即是 入参的 Promise 对象。
console.log(p0 === p1);
传入 thenable 对象,返回 Promise 对象跟随 thenable 对象的最终状态。
ES6 Promises 里提到了 Thenable 这个概念,简单来说它就是一个非常类似 Promise 的东西。最简单的例子就是 jQuery.ajax,它的返回值就是 thenable 对象。但是要谨记,并不是只要实现了 then 方法就一定能作为 Promise 对象来使用。
//如果传入的 value 本身就是 thenable 对象,返回的 promise 对象会跟随 thenable 对象的状态。
let promise = Promise.resolve($.ajax('/test/test.json'));// => promise对象
promise.then(function(value){
console.log(value);
});
返回一个状态已变成 resolved 的 Promise 对象。
let p1 = Promise.resolve(123);
//打印p1 可以看到p1是一个状态置为resolved的Promise对象
console.log(p1)
Promise.reject
类方法,且与 resolve 唯一的不同是,返回的 promise 对象的状态为 rejected。
Promise.prototype.then
实例方法,为 Promise 注册回调函数,函数形式:fn(vlaue){},value 是上一个任务的返回结果,then 中的函数一定要 return 一个结果或者一个新的 Promise 对象,才可以让之后的then 回调接收。
Promise.prototype.catch
实例方法,捕获异常,函数形式:fn(err){}, err 是 catch 注册 之前的回调抛出的异常信息。
Promise.race
类方法,多个 Promise 任务同时执行,返回最先执行结束的 Promise 任务的结果,不管这个 Promise 结果是成功还是失败。
Promise.all
类方法,多个 Promise 任务同时执行。如果全部成功执行,则以数组的方式返回所有 Promise 任务的执行结果。 如果有一个 Promise 任务 rejected,则只返回 rejected 任务的结果。
Promise.wrap
回调函数转 Promise
const promiseFoo = Promise.wrap(foo)
promiseFoo(1, 2) .then((data) => { console.log(data) }) .catch((err) => { console.log(err) })
promise解决的问题
promise解决的问题:回调地狱
回调地狱带来的负面作用有以下几点:
- 代码臃肿。
- 可读性差。
- 耦合度过高,可维护性差。
- 代码复用性差。
- 容易滋生 bug。
- 只能在回调里处理异常。
var p1 = new Promise(function(resolve, reject){
resolve(Promise.resolve('resolve'));
});
var p2 = new Promise(function(resolve, reject){
resolve(Promise.reject('reject'));
});
var p3 = new Promise(function(resolve, reject){
reject(Promise.resolve('resolve'));
});
p1.then(
function fulfilled(value){
console.log('fulfilled: ' + value);
},
function rejected(err){
console.log('rejected: ' + err);
}
);
p2.then(
function fulfilled(value){
console.log('fulfilled: ' + value);
},
function rejected(err){
console.log('rejected: ' + err);
}
);
p3.then(
function fulfilled(value){
console.log('fulfilled: ' + value);
},
function rejected(err){
console.log('rejected: ' + err);
}
);
控制台输出:
p3 rejected: [object Promise]
p1 fulfilled: resolve
p2 rejected: reject
说明
Promise回调函数中的第一个参数resolve,会对Promise执行”拆箱”动作。即当resolve的参数是一个Promise对象时,resolve会”拆箱”获取这个Promise对象的状态和值,但这个过程是异步的。p1”拆箱”后,获取到Promise对象的状态是resolved,因此fulfilled回调被执行;p2”拆箱”后,获取到Promise对象的状态是rejected,因此rejected回调被执行。但Promise回调函数中的第二个参数reject不具备”拆箱“的能力,reject的参数会直接传递给then方法中的rejected回调。因此,即使p3 reject接收了一个resolved状态的Promise,then方法中被调用的依然是rejected,并且参数就是reject接收到的Promise对象。
promise.then(…).catch(…);与promise.then(…, …);并不等价, 尤其注意当promise.then(…).catch(…);中的then会抛异常的情况下。
promise
.then(...) //返回一个新的promise,如果then之前的promise是rejected则延续
.catch(...); //又返回一个新的promise,如果catch之前的promise是resolved则延续
promise
//返回一个新的promise
//如果then之前的promise是resolved,则由第一个参数返回
//如果then之前的promise是rejected,则由第二个参数返回。
.then(..., ...);
例子:
const fn = () => {
throw 2;
}
//promise.then(...).catch(...);
Promise.resolve(1) //{ [[PromiseStatus]]:"resolved", [[PromiseValue]]:1 }
.then(v => { //1
fn(); //抛异常了,then返回一个rejected的promise
return 3; //后面不执行了
}) //{ [[PromiseStatus]]:"rejected", [[PromiseValue]]:2 }
.catch(v => { //v是throw的值2
console.log(v); //2
return 4; //catch返回一个resolved且值为4的promise
}); //{ [[PromiseStatus]]:"resolved", [[PromiseValue]]:4 }
//程序最后正常结束
//promise.then(..., ...);
Promise.resolve(1) //{ [[PromiseStatus]]:"resolved", [[PromiseValue]]:1 }
.then(
v => { //1
fn(); //抛异常了,then返回一个rejected的promise
return 3; //后面不执行了
},
v => { //这里只有then之前是rejected才执行
console.log(v);//不执行
return 4; //不执行
}
); //{ [[PromiseStatus]]:"rejected", [[PromiseValue]]:2 }
//程序最后抛异常:Uncaught (in promise) 2
var p = new Promise(function(resolve, reject){
resolve(1);
});
p.then(function(value){ //第一个then
console.log(value);
return value*2;
}).then(function(value){ //第二个then
console.log(value);
}).then(function(value){ //第三个then
console.log(value);
return Promise.resolve('resolve');
}).then(function(value){ //第四个then
console.log(value);
return Promise.reject('reject');
}).then(function(value){ //第五个then
console.log('resolve: '+ value);
}, function(err){
console.log('reject: ' + err);
})
答案:
1
2
undefined
"resolve"
"reject: reject"