1.Promise对象的介绍以及基本使用
1.1 基本的介绍
基础:一个对象,有三种状态:
pending(进行中)fulfilled(已执行)rejected(已拒绝)
是能够异步执行(要了解JS的事件执行机制)对象。
仅此而已。
1.2 基本的使用
let p = new Promise((resolve, reject) => {
// 做一些事情
// 然后在某些条件下resolve,或者reject
if (/* 条件随便写^_^ */) {
resolve()
} else {
reject()
}
})
p.then(() => {
// 如果p的状态被resolve了,就进入这里
}, () => {
// 如果p的状态被reject
})
2.Promise对象常用的方法和使用场景
2.1 Promise.then()
Promise对象的then方法主要用途是为promise对象的状态注册回调函数。
参数有两个,第一个是从promise对象中的resolve过来应该执行的回调函数,第二个参数是从promise对象中reject过来应该执行的回调函数,第二个参数是可选项。
then方法的返回值是什么呢?返回的还是Promise对象,没错,就是因为这样所以说Promise可以解决传说中的“地狱回调”问题。因为返回的还是一个异步的操作,如果要执行一个后续的任务,我们只能等前一个任务完成之后才有回调。
var pro = new Promise( function(resolve, reject) {
if( 1 === 2) {
resolve(['参数一','参数二'])
}else {
throw new Error('模拟发生在Promise里面的错误')
}
}).then(
/* .then 可以传两个函数,第一个在resolve的时候调用,第二个在reject的时候调用,两个函数的参数只有一个,
如果有多个参数需要传递可以使用数组或对象的形式 */
function funcResolve([arg1,arg2]) {
console.log(arg1);
console.log(arg2);
},
function funcReject(rejection) {
console.log('then的接收Promise的reject错误函数:', rejection);
throw new Error('模拟发生在rejection里面的错误')
}
).catch(
function(err) {
console.log('发生错误:', err);
}
)
2.2 Promise.catch()
Promise对象的.catch方法用于注册reject的回调函数,同时该回调也是程序出错的回调函数,就是说,如果前面的程序出错了也是会进入该函数执行的。和.then一样返回的一个promise对象。
catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数
什么时候调用这里面的方法:
- Promise里面抛出的错误
- 接收Error和reject的错误执行回调
- then里面的错误
注:一般来说,不要在then方法里面定义Reject状态的回调函数(即then的第二个参数),总是使用catch方法。
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
一般来说,catch方法之中,还能再抛出错误。
2.3 Promise.all()
参数:Promise.all的 参数是接受一个数组作为参数的,数组的元素指定是多个Promise实例。
作用:.all函数的作用是最后返回一个状态(resolve或者reject),根据参数的数据传递进来的。大概的例子如下:
const promise = new Promise.all([p0,p1,p2])
在上面的举例中,传进去的数组中的p0p1p2,都应该是promise实例,如果不是的,会自动调用Promise.resolve()方法进行转换。 那这个promise什么时候才会返回一个resolve的状态呢? 只有全部的元素都返回了resolve的状态才会最终返回一个resolve给promise,其他的情况都是reject
返回值:以上情况就是p0,p1,p2都是fulfilled状态的话,promise才会状态变为fulfilled,此时p0、p1、p2的返回值组成一个数组,传递给promise的回调函数。
2.4 Promise.race()
参数:Promise.race的 参数是接受一个数组作为参数的,数组的元素指定是多个Promise实例。
作用:同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const promise = new Promise.all([p0,p1,p2])
上面代码中,只要p0、p1、p2之中有一个实例率先改变状态,promise的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
返回值:以上情况就是p0,p1,p2都是fulfilled状态的话,promise才会状态变为fulfilled,此时p0、p1、p2的返回值组成一个数组,传递给promise的回调函数。
2.5 Promise.resove()
参数:一个对象、Promise实例、一个thenable对象、原始值
作用:将该对象转化为resolve状态的Promise实例。
实例:
var jsPromise = Promise.resolve($.ajax('/whatever.json'));
下面两种写法等价:
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
2.6 Promise.reject()
参数:一个对象
作用:将该对象转化为reject状态的Promise实例。
实例:
var p = Promise.reject('出错了');
// 等同于
var p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s){
console.log(s)
});
// 出错了
上面代码生成一个Promise对象的实例p,状态为rejected,回调函数会立即执行。
3.Promise对象和async、await的区别
关于更多的async、await的基础与使用请关注:www.xyhtml5.com/5027.html
一个面试题:
for (var i = 0; i < 5; i++) {
(function(j) { // j = i
setTimeout(function() {
console.log(new Date, j);
}, 1000);
})(i);
}
console.log(new Date, i);
输出:
现要修改输出的顺序为:0 -> 1 -> 2 -> 3 -> 4 -> 5
ES6之前
for (var i = 0; i < 5; i++) {
(function(j) { // j = i
setTimeout(function() {
console.log(new Date, j);
}, 1000);
})(i);
}
setTimeout(() => {
console.log(new Date, i);
}, 1000);
ES6 Promise
new Promise(function(resolve) {
for (var i = 0; i < 5; i++) {
(function(j) { // j = i
setTimeout(function() {
console.log(new Date, j);
}, 1000);
})(i);
}
resolve(i)
}
).then(
val => {
setTimeout(() => {
console.log(new Date,val);
}, 1000);
}
)
ES7 async await
async function test() {
for (var i = 0; i < 5; i++) {
await (function(j) {
setTimeout(function() {
console.log(new Date, j);
}, 1000);
})(i);
}
await (() => {
setTimeout(() => {
console.log(new Date, i)
}, 1000); })()
}
test()
ES7 async await + Promise
const sleep = (timeountMS) => new Promise((resolve) => {
setTimeout(resolve, timeountMS);
});
(
async () => { // 声明即执行的 async 函数表达式
for (var i = 0; i < 5; i++) {
await sleep(1000);
console.log(new Date, i);
}
await sleep(1000);
console.log(new Date, i);
}
)();
4.总结
上面这样构造promise实例,然后调用.then.then.then的编写代码方式,就是promise。
其基本模式是:
- 将异步过程转化成promise对象
- 对象有3种状态
- 通过.then注册状态的回调
- 已完成的状态能触发回调
采用这种方式来处理编程中的异步任务,就是在使用promise了。
所以promise就是一种异步编程模式。
首先,promise实例有三种状态:
pending(进行中)fulfilled(已执行)rejected(已拒绝)
fulfilled和rejected有可以说是已成功和已失败,这两种状态又归为已完成状态
resolve和reject
调用resolve和reject能将分别将promise实例的状态变成fulfilled和rejected,只有状态变成已完成(即fulfilled和rejected之一),才能触发状态的回调
Promise API
promise的内容分为构造函数、实例方法和静态方法
- 1个构造函数:
new Promise - 2个实例方法:
.then和.catch - 4个静态方法:
Promise.all、Promise.race、Promise.resolve和Promise.reject
new Promise能将一个异步过程转化成promise对象。先有了promise对象,然后才有promise编程方式。
.then用于为promise对象的状态注册回调函数。它会返回一个promise对象,所以可以进行链式调用,也就是.then后面可以继续.then。在注册的状态回调函数中,可以通过return语句改变.then返回的promise对象的状态,以及向后面.then注册的状态回调传递数据;也可以不使用return语句,那样默认就是将返回的promise对象resolve。.catch用于注册rejected状态的回调函数,同时该回调也是程序出错的回调,即如果前面的程序运行过程中出错,也会进入执行该回调函数。同.then一样,也会返回新的promise对象。- 调用Promise.resolve会返回一个状态为fulfilled状态的promise对象,参数会作为数据传递给后面的状态回调函数
Promise.reject与Promise.resolve同理,区别在于返回的promise对象状态为rejected
Promise.all
用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p的状态由p1、p2、p3决定,分成两种情况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
Promise.race
同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.resolve 有时需要将现有对象转为 Promise 对象
Promise.reject 会返回一个新的 Promise 实例,该实例的状态为rejected。