文章目录
Promise
含义
- Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了
Promise
对象。 - 从语法上说,Promise 是一个
对象
,从它可以获取异步操作
的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。 - Promise 对象代表异步操作 => 其中有三种状态:
pending(进行中)
、fulfilled(已成功)
和rejected(已失败)
。 - Promise状态改变的过程:从
pending变为fulfilled
和从pending变为rejected
,一旦状态确定为其中的一种,那么就不会再发生改变。 - Promise 的缺点:一旦新建它就会立即执行,无法中途取消。其次,如果不设置
回调函数
,Promise内部
抛出的错误,不会反应到外部。第三,当处于pending状态
时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
基本用法
- Promise对象是一个构造函数,用来生成
Promise实例
var promise1 = new Promise(function(resolve, reject){
let index = 0;
index++;
if (index <= 2)
resolve('Jack')
throw new Error('Not function!')
})
.then(data => console.log(data))
.catch(err => console.log(err))
// 理解一下上面的代码:首先我们应用Promise对象进行实例化,promise1是
// Promise的实例化对象。Promise里面接受一个函数作为参数 =>
// 在函数内:判断 index 的值是否 <=2,成功执行 resolve函数,否则抛出错误
// 内部抛出错误将会被 catch 捕捉,最后打印
// 下面会详细介绍 then 和 catch
-
resolve
函数的作用是,将Promise对象的状态从“未完成”变为“成功”
(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
-
reject
函数的作用是,将Promise对象的状态从“未完成”变为“失败”
(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是
resolve
和
reject
。
- Promise实例生成以后,可以用
then
方法分别指定resolved状态
和rejected状态
的回调函数。(如上述代码)
注意①:
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('resolved.');
});
console.log('Hi!');
// Promise
// Hi!
// resolved
- Promise 新建后立即执行,所以首先输出的是Promise。然后,
then方法
指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。
注意②
- 注意,调用
resolve
或reject
并不会终结 Promise
的参数函数的执行。
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1
// 在控制台打印的语句依然可以执行,所以为了不必要的麻烦,我们通常
// 采用下面这一种写法。
new Promise((resolve, reject) => {
return resolve(1);
// 后面的语句不会执行
console.log(2);
})
Promise.prototype.then()
Promise 实例
具有then
方法,也就是说,then方法是定义在原型对象Promise.prototype
上的。- then方法返回的是一个
新的Promise实例
// promise1为 Promise 的实例
promise1.then(function(data) {
return data;
}).then(function(post) {
return post+1; // 相当于 data + 1
});
// 上面的代码使用then方法,依次指定了两个回调函数。第一个回调函数完成以
// 后,会将返回结果作为参数,传入第二个回调函数。
- 这时,前一个回调函数,有可能返回的还是一个
Promise对象
(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
promise1.then(function(data) {
return new Promise(function(resolve, reject){})
}).then(function(){}, function(){});
// 如果状态为 resolve,那么执行then里面的第一个函数,否则执行第二个
// 补充:then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)
// 是rejected状态的回调函数。
// 下面会介绍捕获内部错误的 catch 方法
Promise.prototype.catch()
Promise.prototype.catch
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
let promise = new Promise(function(resolve, reject){})
promise.then(function(){})
.catch(function(){})
// promise 为 Promise的实例。
//如果该对象状态变为resolved,则会调用then方法指定的回调函数;如果异步操作
//抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这
//个错误。
//另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。
再次引用上面举过的例子:
var promise = new Promise(function(resolve, reject){
let index = 0;
index++;
if (index <= 2)
resolve('Jack')
throw new Error('Not function!')
})
.then(data => console.log(data))
.catch(err => console.log(err)) // 'Not function!'
// 我们主动抛出的错误会被 catch捕获到,然后再控制台打印
// 假如 状态已经由 pending => resolve, 那么再次抛出错误就无效了
- 一般总是建议,Promise 对象后面要跟catch方法,这样可以处理 Promise 内部发生的错误。catch方法返回的还是一个 Promise 对象,因此后面还可以接着调用then方法。
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
});
};
someAsyncThing()
.catch(function(error) {})
.then(function() {});
// 如果实例不发生错误的话,会继续执行 .then后面的内容,否则会提前被 catch
// 捕获到,这样提高了排错的效率。
- catch 内部还能抛出错误,给下一个 catch 捕获到。
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
});
};
someAsyncThing()
.catch(function(error) {
throw new Error('ExistedProblem')
}).catch(function(){})
// 后面的 catch 会捕获到前一个 catch 抛出错误进而进行处理。
Promise.prototype.finally()
finally
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
// promise 是 Promise 的实例
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
// 此时不管 promise 的状态变为 resolve执行.then或者 状态变为 reject执行
// catch, finally 都会执行
- 从上面的代码可知,
finally
方法的回调函数不接受任何参数
,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
// resolve 的值是 undefined
Promise.resolve(2).then(() => {}, () => {})
// resolve 的值是 2
Promise.resolve(2).finally(() => {})
// reject 的值是 undefined
Promise.reject(3).then(() => {}, () => {})
// reject 的值是 3
Promise.reject(3).finally(() => {})
- 从上面的代码可知,
finally
方法总是会返回原来的值。
Promise.all()
Promise.all()
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
// 其中 promise 和 promise_1 均为 Promise 实例
var promise_2 = Promise.all([promise, promise_1])
-
(1)只有
promise, promise_1
的状态都变成fulfilled
,promise_2
的状态才会变成fulfilled,此时promise, promise_1
返回值组成一个数组,传递给p的回调函数。 -
(2)只要
promise, promise_1
之中有一个 被rejected
,promise_2
的状态就变成rejected,此时第一个被reject的实例
的返回值,会传递给p的回调函数。
Promise.all()
方法可以接受一个数组作为参数,也可接受具有
Iterator 接口
且返回的每个成员均为
Promise 实例
注意:如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。
var promise = new Promise(function(resolve, reject){
let index = 4;
index++;
if (index <= 2)
resolve('Jack')
throw new Error('Not function!')
})
.then(data => console.log(data))
.catch(err => console.log(err)) // 最后执行的是这个
var promise_1 = new Promise(function(resolve, reject){
return resolve('summary')
})
var promise_2 = Promise.all([promise, promise_1])
promise_2.then(function(){console.log('yes')})
.catch(function(){err => console.log(err)}) // 最后是不会执行的
// .catch(function(){console.log('失败了')}) => 例外:会执行
console.log(promise_2) // resolved
// 其实不执行指的是 Promise 实例不会传递错误指数给 catch,所以参数 err
// 等于 undefined, 所以最后才会没有结果,但是捕获还是照样进行的。
// 当promise的catch 执行完后,他返回一个新的Promise对象,这个对象的状态为 // resolve, 与 promise_1合起来,所以promise_2的状态为 resolved
// 这段代码其实本质就是判断 index是否小于等于2,大家也可以把 promise_1的
// catch删去看下最后控制台打印是否是 promise_2的 catch()
Promise.race()
// 其中 promise 和 promise_1 均为 Promise 实例
var promise_2 = Promise.race([promise, promise_1])
-
只要
promise、promise_1
之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例
的返回值,就传递给p的回调函数。
Promise.race()
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
var promise = new Promise(function(resolve, reject){
let index = 4;
index++;
if (index <= 2)
resolve('Jack')
throw new Error('Not function!')
})
.then(data => console.log(data))
.catch(err => console.log(err))
var promise_1 = new Promise(function(resolve, reject){
return resolve('summary')
})
var promise_2 = Promise.race([promise, promise_1])
promise_2.then(function(){console.log('yes')})
.catch(function(){err => console.log(err)})
console.log(promise_2) // rejected
// 结果上面 all()方法一样,最后输出的是 promise抛出的错误
// 但是不同的是,此时的 promise_2状态为 reject