Promise/A+规范
promise代表一个异步操作的最终结果,和promise交互的主要方式是使用.then方法,它会注册一些回调函数,用来接收promise的最终结果或者promise无法完成的原因,promise/A+规范着重关注then方法。
术语:
- promise是一个具有then方法对象或者函数
- thenable是指一个对象或者函数具有then方法
- value是任意合法的js对象,包括undefined、a thenable对象或者promise
- exception是一个可以throw的value值;
- reason是指示promise失败的value值
要求:
-
promise状态
一个promise只能是以下三种状态之一:pending、fulfilled、rejected
-
当状态是pending时,它可以转移成fulfilled或者rejected
-
当状态是fulfilled时
- 它无法再转移成其他状态
- 有一个不变的value值
-
当状态是rejected时
- 它无法再转移成其他状态
- 有一个不变的reason值
-
-
then方法
promise必须有一个then方法,可以用来获取目前后者最终的结果或者失败原因;它能接受两个参数
promise.then(onFulfilled, onRejected)-
onFulfilled和onRejected都是可选参数,非必须
- onFulfilled 默认是function(value){return value}
- onRejected默认是function(reason){throw reason}
-
如果onFulfilled是一个函数,
- onFulfilled会在promise状态为fulfilled后执行,并且value为第一个参数
- onFulfilled不会在promise状态不为fulfilled时执行
- onFulfilled最多执行一次
-
如果onRejected是一个函数,
- onRejected会在promise状态为rejected后执行,并且reason为第一个参数
- onFulfilled不会在promise状态不为rejected时执行,也不会执行多次
- onRejected最多执行一次
-
onFulfilled和onRejected会在本地执行堆栈执行后才会调用(异步)
-
onFulfilled和onRejected是作为函数执行(没有this关键字)
-
同一个promise的then方法可以多次调用
- 如果promise是fulfilled,所有的onFulfilled都会按照then方法注册顺序进行执行;
- 如果promise是rejected,所有的onRejected都会按照then方法注册顺序进行执行;
-
then方法必须返回一个promise
promise2 = promise1.then(onFulfilled, onRejected);- 如果onFulfilled或者onRejected返回value x,进行promise解析过程【[Resolve]】(promise2,x)
- 如果onFulfilled或者onRejected抛出了一个异常e,则promise2会被rejected,e作为reason
- 如果onFulfilled不是一个函数并且promise1 fulfilled,则promise2也是fulfillid状态,value值和promise1相同。
- 如果onRejected不是一个函数并且promise1 rejected,则promise2也是rejected状态,reason值和promise1相同。
-
-
promise解析过程【[Resolve]】(promise,x)
promise的解析过程是要给抽象的操作,入参是一个promise和一个值x。如果x是要thenable的,他会试图让promise采纳x的状态和值。否则,他会设置promise状态为fulfilled,值为x。
解析过程如下:
-
如果promise和x指向同一个对象,则reject这个promise,reason设置为TypeError(避免then的调用栈循环)
-
如果x是一个promise,promise将使用x的状态
- 如果x是pending,则promise也是pending,直到x变为fulfilled或者rejected
- 如果x是fulfilled, 则promise也用x的value进行fulfill(resolve)
- 如果x是rejected,则promise也使用x的reason进行reject
-
否则,如果x是一个对象或者函数
-
then赋值为x.then
-
如果x.then抛出异常e,则reject promise,原因reason值为e
-
如果then是一个函数,执行下面
then(resolvePromise,rejectPromise)-
如果resolvePromise执行了,值为y,则进行解析过程【[Resolve]】(promise,y)
-
如果rejectPromise执行了,reason为r,则promise状态设为rejected,reson设为r。
-
如果resolvePromise和rejectPromise都被调用了,或者使用相同的参数调用了多次,则只有第一次的调用生效,后面的调用都将被忽略。
-
如果then方法的调用抛出了异常e,
- 如果resolvePromise或者rejectPromise被调用了,则忽略e
- 否则,promise将被reject,e作为reason值。
-
如果then不是一个函数,则promise 进行fulfill,值为x
-
-
-
如果x不是一个对象或者函数,fulfill 这个promise,值为x
异步编程
-
promise可以支持链式调用,解决回调地狱的问题
asyncFunc1({
xxx;
asyncFunc2({
asyncFunc3({
xxx;
})
xxx;
})
})
使用promise可以封装异步操作,异步逻辑和回调处理可以分开编写
const p = new Promise((resolve,reject)=>{
if(status){
resolve(val);
}else{
reject(err);
}
})
p.then((val)=>{
//resolve callback
sucFunc1(val);
},(err)=>{
//reject callback
errFunc2(err);
})
function sendAjax(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
};
});
}
sendAjax("https://www.baidu.com").then((data) => console.log(data));
Promise的状态
promise实例对象有两个属性:PromiseState,PromiseResult。
- 【PromiseState】
- pending 初始状态
- fullfilled 成功
- rejected 失败
- [PromiseResult]
成功时,值为resovle的value;
失败时,值为reject的value;
非promise的对象,值为undefined;
- 改变PromiseState状态的方式:
resolve:pending-->fullfilled;
reject/throw: pending-->rejected
PromiseState的值一旦改变就不会再发生变化;
Promise的API
- 构造函数
const promise = new Promise((resolve,reject)=>{xxx})
-
promise.then.catch代码结构
异常穿透 最后的catch可以捕获前面的所有promise和then中出现的异常和reject的结果
-
Promise.resolve()
- Promise.reject()
- Promise.all([promise1,promise2,....])
promise数组都成功才成功,成功结果为所有promise的结果数组;
有一个promise失败,则promise.all返回失败的promise,结果为失败的promise值
- Promise.race([promise1,promise2,....])
由最先返回的promise决定最终promise状态和结果
- 中断promise链
可以在then中创建一个pending状态的promise。
const p =new Promise((resolve,reject)=>{
resolve();
})
p.then({
//中断
return new Promise(()=>{})
}).then(xxx).then(xxx)
手写promise
-
构造函数
浏览器F12查看Promise的构造函数
构造函数执行器excurtor写明promise的同步或者异步处理逻辑,Promise中的核心resolve和reject函数方法,用于改变promise的状态和值,对异步逻辑进行回调触发。
function Promise(excutor) {
//状态
this.PromiseStatus = "pending";
//promise结果
this.PromiseResult = undefined;
//异步执行结果回调函数定义,采用数组的形式可以支持绑定多个回调函数
this.callback = [];
//常用写法,解决this指向问题
const that = this;
//resolve函数
function resolve(val) {
//判断状态,保证promise状态只能改变一次
if (that.PromiseStatus !== "pending") return;
//改变promiseStatus对象状态,
that.PromiseStatus = "fullfilled";
//设置promiseResult值
that.PromiseResult = val;
//调用成功的回调函数
that.callback.forEach((item) => {
item.onResolved(val);
});
}
//reject函数
function reject(err) {
//判断状态,保证promise状态只能改变一次
if (that.PromiseStatus !== "pending") return;
//改变promiseStatus对象状态
that.PromiseStatus = "rejected";
//设置promiseResult值
that.PromiseResult = err;
//调用成功的回调函数
that.callback.forEach((item) => {
item.onRejected(err);
});
}
//同步调用
try {
excutor(resolve, reject);
} catch (error) {
reject(error);
}
}
-
then API
then 写回调逻辑,定义promise状态改变后需要执行的操作,返回值也是一个promise
Promise.prototype.then = function (onResolved, onRejected) {
//this指向问题
const self = this;
//实现异常穿透,增加默认的onRejected回调函数
if (typeof onRejected !== "function") {
onRejected = (reason) => {
throw reason;
};
}
if (typeof onResolved !== "function") {
onResolved = (value) => {
return value;
};
}
//then返回的是一个promise,支持链式调用
return new Promise((resolve, reject) => {
//定义处理函数,type会回调函数类型
function callback(type) {
try {
let result = type(self.PromiseResult);
//如果result是一个promise,则该promise的状态和结果为返回的结果
if (result instanceof Promise) {
result.then(
(v) => {
resolve(v);
},
(r) => {
reject(r);
}
);
} else {
//返回的promise对象状态为成功,值为result,result可能会undifined
resolve(result);
}
} catch (err) {
reject(err);
}
}
//promiseStatus为fullfilled或者rejected表明在then函数定义时,promise执行结果已经执行完 成,可以直接触发回调函数
if (this.PromiseStatus === "fullfilled") {
callback(onResolved);
}
if (this.PromiseStatus === "rejected") {
callback(onRejected);
}
//对于异步操作,then定义时,promiseStatus并没有发生改变,此时做的事情是将回调函数保存promise对象中去,等待异步操作执行resolve或者reject方法是触发回调函数执行;
if (this.PromiseStatus === "pending") {
//保存回调函数
this.callback.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
},
});
}
});
};
- catch API
catch可以利用then方法的第二个回调函数实现,resolve回调设置成undefined
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
};
\