ES6之promise基础篇

摘要:promise,ES6新增特性,是javascript实现异步的方法之一,在这里对promise的基础知识做介绍。

promise

作用:异步编程的一种解决方案
三种状态:

  • pending(进行中)
  • fulfilled(已完成,又称resolved)
  • rjected(已失败)

状态只有两种变化,状态只能从pending变化为fulfilled或者rjected,只有异步操作的结果可以决定当前是哪一种状态,并且状态一旦改变,就不会再发生变化。

  1. pending->fulfilled
  2. pending->rjected

使用例子

promise是一个构造函数,需要用new来生成promise的实例,在promise实例中执行的代码是同步执行的,即new之后代码是立即执行的,Promise实例化的时候传入的是一个函数,函数可接受两个参数,分别是resolve和reject,这两个参数其实是两个函数,当异步操作结束的时候进行调用。

  • resolve:将实例的状态从Pending->fulfilled,并且将异步操作成功的结果作为参数传递出去
  • reject:将实例的状态从Pending->rjected,并且将异步操作报出的错误作为参数传递出去
  • promise.then:该方法接受两个回调函数作为参数,分别为onFulfilled和onRejected,即状态变为fulfilled和状态变为rejected的时候调用的函数
  • promise.catch:该方法接受一个回调函数作为参数,其实就是捕获错误的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var promise = new Promise(function(resolve, reject){
// result为异步操作的结果
if(result == 'succ') {
// 异步操作成功时执行的操作
resolve(result);
} else {
// 异步操作失败时执行的操作
reject(error);
}
});
promise.then(function(res){
console.log('resolve:'+res);
},function(err){
console.log('reject:'+err);
}).catch(function(err){
console.log('catch:'+err);
});

promise方法

prmoise提供的方法有一下6个,下面对这几个方法进行介绍

  1. Promise.prototype.then(onFulfilled, onRejected)
  2. Promise.prototype.catch(onRejected)
  3. Promise.all(iterable)
  4. Promise.race(iterable)
  5. Promise.resolve(iterable)
  6. Promise.reject(reason)

Promise.prototype.then(onFulfilled, onRejected)

Promise的实例具有then方法,调用之后会返回一个新的promise实例,如果then中有onRejected函数并且promise有reject错误,执行完then方法之后,返回的新promise实例的状态就会变为fulfilled。

then是Promise实例的回调函数,即当Promise实例的状态发生改变时调用的函数,它接受两个参数,第一个参数onFulfilled是当状态变为fulfilled的回调函数(执行resolve()函数),第二个参数是当状态变为rejected的回调函数(执行reject()函数)。

Promise实例的方法是可以链式调用的,看到下面的例子,第一个回调函数的返回值会传到下一个回调函数的参数中,如果第一个函数没有返回值,则第二个回调函数的参数则为undefined。(这里的第一行代码是直接调用Promise.resolve(),这其实是快速获取状态为resolved的promise实例)。

1
2
3
4
5
6
7
var promise = Promise.resolve();
promise.then(function(res){
console.log(res); // undefined
return 'next res';
}).then(function(res){
console.log(res); // 'next res'
});

Promise.prototype.catch(onRejected)

promise的实例也具有catch方法,用于捕获代码中抛出的异常(也包括reject抛出的异常),调用之后会返回一个新的promise实例,一旦错误被捕获,新promise实例的状态就是fulfilled。

异常也可以在then中被捕获,被then捕获的异常就不会被catch捕获了。示例一中promise抛出的错误被then的onRejected捕获了,onRejected中又抛出了错误,这里的错误就被catch捕获了。

Promise对象的错误是可以冒泡的,如果错误没有被捕获,就会一直像后传递直到被捕获为止。示例二中promise抛出的错误在then中没有被捕获,所以就会冒泡到catch中被捕获。

如果Promise对象已经执行了resolve()函数,在之后再抛出的错误就不会被捕获了,在示例三中Promise对象已经执行了resolve(),所以之后抛出的错误也不会被捕获,因为状态一旦改变,就不会再变了,所以后续的错误也不会被捕获。这里Promise对象抛出的错误不会传递到外层代码,所以也不会看到有报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 示例一:then中捕获promise中reject抛出的异常,catch中捕获onRejected抛出的异常
var promise = Promise.reject('err');
promise.then(null, function(err){
console.log(err); // 'err'
throw 'next err';
}).catch(function(err){
console.log(err); // 'next err'
});
// 示例二:error没有被then捕获,则会冒泡到catch中被捕获
promise.then().catch(function(err){
console.log(err); // 'err'
});
// 示例三:当promise的resolve之后,再之后抛出的错误就不会被捕获了
var promise = new Promise(function(resolve,reject){
resolve('123');
throw '456';
});
promise.then().catch(function(err){
console.log(err);
});

Promise.all(iterable)

Promise.all方法是将多个promise实例,包装成一个新的promise实例。
promise的状态由all中所有的promise的状态决定:

  • fulfilled:当all中所有promise的状态都为fulfilled时promise的状态为fulfilled
  • rejected:当all中其中一个promise的状态为rejected时promise的状态为rejected
    promise的返回值为all中所有的返回值组成的数组。

如果promise参数数组中的对象不是promise对象,则会先调用Promise.resolve对象将其转化为promise对象。
iterable参数可以不是数组,但是必须含有Iterator接口。

示例中,promise2状态率先变为fulfilled,但是promise1的状态还是pending,所以promise的状态还是pending,过了5s之后,promise1的状态变为fulfilled,即all中所有的promise对象的状态都变为fulfilled,所以promise的状态就变为了fulfilled,返回值则为all中所有的返回值组成的数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
var promise1 = new Promise(function(resolve){
setTimeout(function(){
resolve('123');
},5000);
});
promise1.then(function(res){
console.log(res);
});
var promise2 = Promise.resolve('456');
var promise = Promise.all([promise1,promise2]);
promise.then(function(res){
console.log(res); // ['123','456']
});

Promise.race(iterable)

Promise.race(iterable)方法是将多个promise实例包装成一个promise实例。promise的状态由race中promise的状态决定,率先改变状态的promise会把状态和返回值传递给promise。

示例中,promise是由promise1和promise2包装成的,promise2的状态率先转变为fulfilled,所以promise的状态就采用了promise2的状态和返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
var promise1 = new Promise(function(resolve){
setTimeout(function(){
resolve('123');
},5000);
});
promise1.then(function(res){
console.log(res);
});
var promise2 = Promise.resolve('456');
var promise = Promise.race([promise1,promise2]);
promise.then(function(res){
console.log(res); // '456'
});

Promise.resolve(iterable)

Promise.resolve(iterable)方法返回一个新的promise实例,实例的状态为fulfilled。

这里可以分三种情况:

  1. 参数为promise实例:
    此时返回的是传入的promise实例,看到示例一,这里promise1是Promise.resolve(promise)执行返回的结果,参数为promise,这时promise1其实就是promise。
  2. 参数为thenable对象:
    thenable对象是指具有then方法的对象,在示例二中Promise.resolve(thenable)传入的参数是thenable对象,此时,该方法会将thenable对象转换为promise对象,然后立即执行then方法。
  3. 参数为其他对象:
    当Promise.resolve(iterable)传入的参数既不是promise实例也不是thenable对象时,该方法会返回一个promise实例,返回值即为传入的iterable。在示例三中,参数传入的是什么,promise实例的返回值就是什么。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 示例一
var promise = Promise.resolve('123');
var promise1 = Promise.resolve(promise);
promise1 === promise // true

// 示例二
var thenable = {
then: function(resolve, reject){
resolve('123');
}
}
var promise = Promise.resolve(thenable);

// 示例三
var promise = Promise.resolve({a:1});
var promise = Promise.resolve([1,2,3]);
var promise = Promise.resolve('123');
var promise = Promise.resolve();

Promise.reject(reason)

Promise.reject(reason)方法返回一个新的promise实例,实例的状态为rejected,reason为抛出的错误。在下面示例中列出了resolve参数的三种情况,其实每一种都是一样的,的Promise.reject(reason)的参数reason会直接做为错误被捕获。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var promise = Promise.reject('123');
promise.catch(function(err){
console.log(err); // '123'
});

var thenable = {
then: function(resolve, reject){
reject('123');
}
}
var promise = Promise.reject(thenable);
promise.catch(function(err){
console.log(err); // thenable
});

var promise = Promise.reject();
var promise1 = Promise.reject(promise);
promise1.catch(function(err){
console.log(err); // promise
});