Promise和async都是用于异步操作的方法,async在异步操作方面比Promise更加方便,语法更加易于理解。
1.Promise基本用法
-
Promise为异步操作提供统一的接口,充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口。
-
Promise可以让异步操作写起来就像写同步操作的流程,而不必一层一层的写嵌套函数。
-
Promise是一个对象,也是一个构造函数,用来生成Promise实例。如下:
//Promise是一个对象,也是一个构造函数,可以直接使用new运算符 function fun1(resolve,reject){ //异步代码 setTimeout(function(){ console.log('成功执行1234'); },1000); } //无需调用就输出成功执行1234 var promise1 = new Promise(fun1);//'成功执行1234'
上面代码,Promise构造函数接受一个回调函数fun1作为参数,fun1里是异步操作的代码(这里每隔1秒执行一次),然后返回的promise1就是一个Promise实例。
函数fun1中传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。
-
Promise实例有一个then方法,用来指定下一步的回调函数。如下:
var promise1 = new Promise(fun1);//'成功执行1234' promise1.then(fun2);
上面的代码中,fun1的异步代码执行完后,就会执行fun2。传统写法可能需要把fun2作为回调函数传入fun1,比如:fun1(fun2),异步操作完成后,在fun1内部调用fun2。
而Promise使得fun1和fun2变成了链式写法,对于多层嵌套的回调函数特别的方便,可读性好。
-
Promise的设计思想
-
Promise的设计思想:所有异步任务都返回一个Promise实例。
-
用法:
(new Promise(fun1)).then(fun2) .then(fun3) .then(fun4);
-
2.Promise对象的状态
Promise对象通过自身的状态来控制异步操作。
Promise实例有三种状态:
-
1.异步操作方法未完成(pending)
-
2.异步操作成功(fulfiled)
-
3.异步操作失败(rejected)
三种状态的变化途径只有两种:从"未完成"到"完成",从"未完成"到"失败"。fulfiled和rejected合一起称为resolved(已定型)。
Promise实例的变态变化只可能发生一次,因此Promise的最终结果只有两种的某一个:
1.异步操作成功:Promise实例传回一个值(value),状态变为fulfiled。
2.异步操作失败:Promise实例抛出一个错误(error),状态变化为rejected。
3.then()方法
-
then方法用法和解释
Promise实例的then方法,用来添加回调函数。
then方法可以接受两个回调函数,第一个是异步操作成功时(变为fulfiled状态)的回调函数;第二个是异步操作失败(变为rejected)时的回调函数(该参数可以省略)。一旦状态改变,就调用相应的回调函数。
例如:
//then方法绑定两个回调函数console.log和console.error var promise1 = new Promise(function fun1(resolve,reject){ resolve('successful') }); promise1.then(console.log,console.error);//successful var promise2 = new Promise(function fun1(resolve,reject){ reject('failed') }); promise2.then(console.log,console.error);//failed
输出结果:
resolve和reject是两个函数,她们由JavaScript引擎提供,不用自己实现。
上面代码:then方法绑定两个回调函数:成功时的回调函数console.log和失败时的回调函数console.error(可省略)。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
-
then方法的链式操作
如下:
最后一个then方法,回调函数是console.log和console.error,console.log只显示step3的返回值,而console.error可以显示P1、step1、step2、step3之中任意一个发生的错误。若step1的状态变为rejected,那么step2和step3就不会执行了(因为它们是resolve的回调函数)。Promise开始寻找接下开第一个rejected的回调函数,在上面的代码中是console.error,因此Promise对象的报错具有传递性。
-
Promise的then中只能传递函数,如果为其他类型,例如另一Promise,会被解释为null,此时Promsie的值传递会穿透。
如:
Promise.resolve('foo') .then(Promise.resolve('bar')) .then(function(result){ console.log(result); });//foo //会被解释为: Promise.resolve('foo') .then(null) .then(function(result){ console.log(result); });//foo
4.promise的catch方法
一般来说,不要在then方法里面定义 reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
// bad
promise.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
上面代码中,第二种写法要好于第一种写法,理由是第二种写法可以捕获前面then
方法执行中的错误,也更接近同步的写法(try/catch
)。因此,建议总是使用catch
方法,而不使用then方法的第二个参数。
跟传统的try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise
对象抛出的错误不会传递到外层代码,即不会有任何反应!!!
一般总是建议,Promise
对象后面要跟catch方法,这样可以处理 Promise
内部发生的错误。catch
方法返回的还是一个 Promise
对象,因此后面还可以接着调用then方法!!!
上述部分引自阮一峰老师的《ECMAScript 6 入门》
5.promise的执行顺序
秘诀:promise的异步代码是从then
函数开始的。
有如下代码:
let promise = new Promise(function(resolve, reject) {
console.log('hello');
resolve();
});
promise.then(function() {
console.log('异步resolved.');
});
console.log('Hi!');
// hello
// Hi!
// 异步resolved
输出结果为:
上述部分引自阮一峰老师的《ECMAScript 6 入门》