什么是Promise
Promise是异步编程的一种解决方案,比传统的异步解决方案【回调函数】和【事件】更合理、更强大。
- 从语法上讲,Promise是一个对象,从它可以获取异步操作的信息。
代码书写比较
首先封装一个支持Promise的ajax方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14function request(url,data = {}){
return new Promise((resolve,reject)=>{
$.ajax({
url,
data,
success:function (data) {
resolve(data);
},
error:function (error) {
reject(error);
}
})
});
}。
用 request 方法实现多个互相依赖的网络请求1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18let url1 = 'http://xxx.xxx.1';
let url2 = 'http://xxx.xxx.2';
let url3 = 'http://xxx.xxx.3';
request(url1)
.then((data)=>{
console.log(data);
return request(url2,data)
})
.then((data)=>{
console.log(data);
return request(url3,data)
})
.then((data)=>{
console.log(data)
})
.catch((error)=>{
console.log(error);
});
Promise 的特性
Promise 的状态、
- pending (等待态)
- fulfilled (完成态)
- rejected (拒绝态)
终值与拒因
- 终值: 指的是promise被解决时传递给解决回掉的值
- 拒因:拒绝原因,指在 promise 被拒绝时传递给异常回调的拒绝原因
状态与状态关系,状态与终值和拒因的关系
- pending可以迁移至fulfilled或rejected
- fulfilled 不能迁移至其他状态,必须拥有一个不可变的终值
- rejected 不能迁移至其他状态,必须拥有一个不可变的据因
Promise 的使用
构造函数
Promise 是一个构造函数,使用new操作符返回一个promise对象
构造函数接收一个 excutor函数作为参数
excutor函数有两个函数类型的参数resolve和reject
1 | let p = new Promise((resolve,reject)=>{ |
- 构造函数在调用时,excutor函数会作为同步代码立即执行
- 我们通常在excutor函数中执行我们的异步操作
- 未调用resolve、reject函数时,promise对象的状态为pending
1 | let p1 = new Promise((resolve,reject)=>{ |
- 当调用resolve函数,resolve的参数为非promise对象,非thenable对象
- resolve 函数的参数,作为 promise 对象的终值
- promise 对象的状态变为 fulfilled
1 | let p2 = new Promise((resolve,reject)=>{ |
- 当调用 resolve 函数, resolve 的参数为 promise 对象
- promise 对象的状态、终值、拒因与传入的 promise 对象同步
1
2
3
4
5
6
7let p = new Promise((resolve,reject)=>{
reject('error')
})
let p1 = new Promise((resolve,reject)=>{
resolve(p)
})
// p1 的状态为 rejected ,拒因为 error
- 当调用 resolve 函数, resolve 的参数为 thenable 对象
- 会对 thenable 对象进行展开操作,promise 对象的状态、终值、拒因取决于 thenable 对象的 then 方法调用结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36let thenable1 = {
then:function(resolve,reject){
resolve(1)
}
}
let thenable2 = {
then:function(resolve,reject){
reject(2)
}
}
let thenable3 = {
then:function(resolve,reject){
throw new Error(3)
}
}
let thenable4 = {
then:function(fn1,fn2){
//不调用 fn1 fn2
}
}
let p1 = new Promise((resolve,reject)=>{
resolve(thenable1);
})
let p2 = new Promise((resolve,reject)=>{
resolve(thenable2);
})
let p3 = new Promise((resolve,reject)=>{
resolve(thenable3);
})
let p4 = new Promise((resolve,reject)=>{
resolve(thenable4);
})
// p1 的状态为 fulfilled 终值为 1
// p2 的状态为 rejected 终值为 2
// p3 的状态为 rejected 拒因为 Error:3
// p4 的状态为 pending
- 当调用reject函数,reject函数的参数,作为promise对象的拒因
- promise对象的状态变为rejected
1 | let p3 = new Promise((resolve,reject)=>{ |
Promise对象上的方法
then方法
promise提供一个then方法,用于访问其终值和拒因。
promise的then 方法接受两个参数:1
promise.then(onFulfilled, onRejected)
- onFulfilled函数用于当promise状态变为fulfilled时,接收终值。
- onRejected函数用于当promise状态变为rejected时,接收拒因
1
2
3
4
5
6
7
8new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('异步任务获取的数据')
},50)
}).then((data)=>{
console.log(data)
})
// 异步任务获取的数据
1 | new Promise((resolve,reject)=>{ |
1 | new Promise((resolve,reject)=>{ |
onFulfilled 和 onRejected 参数可选
- 如果 onFulfilled 不是函数,其必须被忽略
- 如果 onRejected 不是函数,其必须被忽略
onFulfilled 的特性
如果onFulfilled是函数:
- 当promise执行结束后其必须被调用,其第一个参数为promise的终值
- 当promise执行结束前其不可被调用
- 其调用次数不可超过1次
onRejected 的特性
如果onRejected是函数: - 当promise执行结束后其必须被调用,其第一个参数为promise的拒因
- 当promise执行结束前其不可被调用
其调用次数不可超过1次
onFulfilled 和 onRejected 的调用时机
当 promise 对象的状态变为 fulfilled 或 rejected 时调用
- onFulfilled、onRejected 永远都是异步调用
- onFulfilled、onRejected 在事件队列中作为微任务来处理
1 | console.log(1); |
onFulfilled 和 onRejected 的调用要求
- onFulfilled 和 onRejected 必须被作为函数调用
- 非严格模式下,this 为全局对象
- 严格模式下,this 为 undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function fn1(){
new Promise((resolve)=>{
resolve();
}).then(function(){
console.log(this)
})
}
function fn2(){
"use strict";
new Promise((resolve)=>{
resolve();
}).then(function(){
console.log(this)
})
}
fn1(); // print: window
fn2(); // print: undefined
then方法的多次调用
- then方法可以被同一个promise对象多次调用
- then方法会返回一个新的promise对象
- 当promise成功执行时,所有onFulfilled需按照其注册顺序依次回调
- 当 promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19let p = new Promise((resolve)=>{
resolve()
});
let p1 = p.then(()=>{
console.log('异步执行,第一个onFulfilled');
});
let p2 = p.then(()=>{
console.log('异步执行,第二个onFulfilled');
});
console.log(p1.constructor === Promise);
console.log(p === p1);
console.log(p === p2);
console.log(p1 === p2);
// print: true
// print: false
// print: false
// print: false
// print: 异步执行,第一个onFulfilled
// print: 异步执行,第二个onFulfilled
then方法的返回值
then方法返回一个promise对象1
promise2 = promise1.then(onFulfilled, onRejected);
若onFulfilled 、onRejected 返回一个非promise
对象、非thenable对象的值x,则promise2的状态变为fulfilled,终值为x1
2
3
4
5
6
7
8
9
10let p = new Promise((resolve,reject)=>{
throw new Error();
});
let p1 = p.then(null,(data)=>{
return '我是p2的终值'
});
p1.then((data)=>{
console.log(data)
});
// print: 我是p2的终值若 onFulfilled 、onRejected 返回一个 promise 对象的值 x ,promise2 的状态、终值、拒因与 x 同步
1 | let p1 = new Promise((resolve,reject)=>{ |
- 若 onFulfilled 、onRejected 返回一个 thenable 对象 ,会对 thenable 对象进行展开操作,promise2 的状态、终值、拒因取决于 thenable 对象的 then 方法调用结果
1 | let thenable1 = { |
若 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 的状态为 rejected,拒因为 e
1
2
3
4
5
6
7
8
9
10let p = new Promise((resolve,reject)=>{
resolve();
});
let p1 = p.then((data)=>{
throw new Error('error')
});
p1.then(null,(err)=>{
console.log(err);
});
// print: Error: error若 onFulfilled 不是函数且 promise1 成功执行, promise2 的状态为 fulfilled 终值为 promise1 的终值
1
2
3
4
5
6
7
8let p = new Promise((resolve,reject)=>{
resolve('我是p1的终值');
});
let p1 = p.then(null,null);
p1.then((data)=>{
console.log(data);
});
// print: 我是p1的终值若 onRejected 不是函数且 promise1 拒绝执行, promise2 的状态为 rejected 拒因为 promise1 的拒因
1
2
3
4
5
6
7
8let p = new Promise((resolve,reject)=>{
reject('我是p1的拒因');
});
let p1 = p.then(null,null);
p1.then(null,(err)=>{
console.log(err);
});
// print:我是p1的拒因若 onFulfilled、onRejected 执行过程中抛出异常,则 promise2 的状态为 rejected 拒因为抛出的异常
1
2
3
4
5
6
7
8
9
10let p = new Promise((resolve,reject)=>{
resolve('我是p的终值');
});
let p1 = p.then((data)=>{
throw new Error('异常')
});
p1.then(null,(err)=>{
console.log(err);
});
// print:Error: 异常
终值和拒因的穿透特性
- 如果 promise 的状态变为 fulfilled,then 方法没有注册 onFulfilled
- then 方法返回的 promise 对象的状态变为 fulfilled
- then 方法返回的 promise 对象的终值与原 promise 对象的终值相同
- 如果 promise 的状态变为 rejected,then 方法没有注册 onRejected
- then 方法返回的 promise 对象的状态变为 rejected
- then 方法返回的 promise 对象的拒因与原 promise 对象的拒因相同
1 | let p1 = new Promise((resolve,reject)=>{ |
- 穿透特性主要用于异常处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17let fn1 = function(){}
let fn2 = function(){}
let fn3 = function(){}
let fn4 = function(){}
let fn5 = function(){}
let onError = function(){};
new Promise((resolve,reject)=>{
setTimeout(function(){
reject()
})
})
.then(fn1)
.then(fn2)
.then(fn3)
.then(fn4)
.then(fn5)
.then(null,onError)
fn1、fn2、fn3、fn4、fn5 都可能发生错误,通过在最后的then函数注册的 onRejected 函数接收可能发生异常错误
catch方法:
catch(fn) 方法实际上是 then(null,fn) 方法的别名,catch 方法的返回值以及 catch 方法中出现异常的情况与调用 then 方法相同1
2
3
4
5
6
7
8
9
10
11new Promise((resolve,reject)=>{
reject()
}).then(null,function(error){
})
// 等同于
new Promise((resolve,reject)=>{
reject()
}).catch(function(error){
})
Promise 的静态方法
Promise.resolve
Promise.resolve 方法用于将现有数据转换为 promise 对象
- 若入参为 promise 对象
返回的 promise 对象的状态、终值、拒因与 Promise.resolve 方法的入参同步
- 若入参为 thenable 对象
会对 thenable 对象进行展开操作,返回的 promise 对象的状态、终值、拒因取决于 thenable 对象的 then 方法调用结果
- 若入参为非 promise 非 thenable 对象
1.返回的 promise 对象的状态为 fulfilled
2.返回的 promise 对象的终值为 Promise.resolve 方法的入参
1 | let p = Promise.resolve(x) |
Promise.reject
- Promise.reject 方法用于返回一个状态为 rejected ,拒因为方法入参的 promise 对象
1
2
3
4
5
6
let p = Promise.reject(x)
// 等价于
let p = new Promise((resolve,reject)=>{
reject(x)
})
Promise.all
Promise.all 方法用于将多个 promise 对象包装成一个新的 promise 对象
1
const p = Promise.all([p1, p2, p3]);
p1、p2、p3 都是 promise 对象,如果不是,调用 Promise.resolve 方法转换为 promise 对象
p 的状态由 p1、p2、p3 决定当 p1、p2、p3 的状态都变成 fulfilled
p 的状态为 fulfilled
此时 p1、p2、p3 的终值组成一个数组,这个数组作为 p 的终值
- 当 p1、p2、p3 的状态有一个变成 rejected
p 的状态变为 rejected
此时第一个状态变为 rejected 的 promise 对象的拒因作为 p 的拒因1
2
3
4
5
6
7let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);
let p3 = 3;
Promise.all([p1,p2,p3]).then((data)=>{
console.log(data); // print: [1,2,3]
})
1 | let p1 = Promise.resolve(1); |
Promise.race
Promise.race 方法同样用于将多个 promise 对象包装成一个新的 promise 对象
1
const p = Promise.race([p1, p2, p3]);
p1、p2、p3 都是 promise 对象,如果不是,调用 Promise.resolve 方法转换为 promise 对象
- p 的状态由 p1、p2、p3 中状态最先变为 fulfilled 或 rejected 的 promise 对象决定
- p 的终值或拒因由最先变更状态的 promise 对象所决定
1 | let p1 = Promise.resolve(1); |
1 | let p1 = new Promise((resolve,reject)=>{ |
Promise 的错误捕获
当 promise 的状态为 rejected 且为对 promise 对象使用 catch 方法,此时的异常信息会被 promise 对象吃掉 可以通过监听 unhandledRejection 事件,专门监听未捕获的reject错误1
2
3
4
5
6
7
8
9// node 环境下
process.on('unhandledRejection', error => {
console.log('unhandledRejection', error);
});
// 浏览器下
window.addEventListener('unhandledrejection',(e)=>{
e.preventDefault();
console.log(e);
});
Promise 的问题
- 无法取消Promise,若没有状态变更,也无法停止 promise 的等待
- 不设定 then 或 catch 方法,构造函数(excutor函数)错误,无法捕获
- 未完成状态时,无法得知是刚开始,还是即将完成
总结:大功告成✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️
参考链接: