promise的串联
当后续的Promise需要用到之前的Promise的处理结果时,需要Promise的串联
Promise对象中,无论是then方法还是catch方法,它们都具有返回值,返回的是一个全新的Promise对象,它的状态满足下面的规则:
- 如果当前的Promise是未决的,得到的新的Promise是挂起状态
- 如果当前的Promise是已决的,会运行响应的后续处理函数,并将后续处理函数的结果(返回值)作为resolved状态数据,应用到新的Promise中;如果后续处理函数发生错误,则把返回值作为rejected状态数据,应用到新的Promise中。
后续的Promise一定会等到前面的Promise有了后续处理结果后,才会变成已决状态
const pro1 = new Promise((resolve, reject) => {
resolve(1)
})
const pro2 = pro1.then(result => {
return result * 2
});
pro2.then(result => console.log(result * 2), err => console.log(err * 3))
- 输出 4
const pro1 = new Promise((resolve, reject) => {
throw 1;
})
const pro2 = pro1.then(result => {
return result * 2
}, err => {
return err * 3; // 3
});
//pro2类型:Promise对象
//pro2的状态:
pro2.then(result => console.log(result * 2), err => console.log(err * 3))
//输出:6
pro2.then的时候运行第一个函数,因为pro1的后续处理没有错误。
const pro1 = new Promise((resolve, reject) => {
throw 1;
})
const pro2 = pro1.then(result => {
return result * 2
}, err => {
throw err; // 1
});
pro2.then(result => console.log(result * 2), err => console.log(err * 3))
// 输出3
- pro抛出了一个错误,pro1的后续处理也抛出了一个错误,那么pro2的后续处理就是rejected,运行第二函数。
const pro1 = new Promise((resolve, reject) => {
throw 1;
})
const pro2 = pro1.then(result => {
return result * 2
}, err => {
return err * 3; // 3
});
//返回的又是一个新的promise 没有pro2什么事
pro1.catch(err => {
return err * 2;
})
//pro1后续处理正常进行,没有抛出错误。所以这里运行第一个函数。
pro2.then(result => console.log(result * 2), err => console.log(err * 3))
//输出:6
如果前面的Promise的后续处理,返回的是一个Promise,则返回的新的Promise状态和后续处理返回的Promise状态保持一致。
const pro1 = new Promise((resolve,reject)=>{
resolve(1);
})
const pro2 = new Promise((resolve,reject)=>{
resolve(2);
})
const pro3 = pro1.then(data=>{
return pro2;
});
pro3.then(data=>{
console.log(data); // 2
})
const pro1 = new Promise((resolve,reject)=>{
resolve(1);
})
const pro2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(2);
},3000)
})
const pro3 = pro1.then(data=>{
console.log('xxxx')
return pro2;
});
pro3.then(data=>{
console.log(data); // 等3s输出2
})
- 先输出 ‘xxxx’ 等3s输出2
const pro1 = new Promise((resolve, reject) => {
resolve(1);
})
const pro2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 3000);
})
pro1.then(result => {
console.log("结果出来了,得到的是一个Promise")
return pro2;
}).then(result => {
console.log(result)
}).then(result => {
console.log(result)
})
- 先输出:结果出来了,得到的是一个Promise
- 等3s输出2
- 由于第二个then返回的undefined,所以等3s输出2后马上输出undefined。
//获取李华所在班级的老师的信息
//1. 获取李华的班级id Promise
//2. 根据班级id获取李华所在班级的老师id Promise
//3. 根据老师的id查询老师信息 Promise
const pro = ajax({
url: "./data/students.json"
})
pro.then(resp => {
for (let i = 0; i < resp.length; i++) {
if (resp[i].name === "李华") {
return resp[i].classId; //班级id
}
}
}).then(cid => {
return ajax({
url: "./data/classes.json?cid=" + cid
}).then(cls => {
for (let i = 0; i < cls.length; i++) {
if (cls[i].id === cid) {
return cls[i].teacherId;
}
}
})
}).then(tid => {
return ajax({
url: "./data/teachers.json"
}).then(ts => {
for (let i = 0; i < ts.length; i++) {
if (ts[i].id === tid) {
return ts[i];
}
}
})
}).then(teacher => {
console.log(teacher);
})
promise 的串联
const MyPromise = (() => {
const PENDING = 'pending', //状态变量
RESOLVED = 'resolved',
REJECTED = 'rejected',
// 符号变量外面的访问不到
promiseStatus = Symbol('PromisrStatus'), //promise的状态
promiseValue = Symbol('promiseValue'), // promise的状态数据
changeStatus = Symbol('changeStatus'), //该变promise的状态
thenables = Symbol('thenables'), //thenables作业队列
catchables = Symbol('catchables'), //catchables作业队列
settleHandle = Symbol('settleHandle'), //后续处理函数
linkPromise = Symbol('linkPromise'); //返回的promise
return class MyPromise {
/**
*
* @param {*} executor 未决阶段(pending状态)下的处理函数
*/
constructor(executor) {
//刚开始为pending
this[promiseStatus] = PENDING;
//刚开始状态数据为undefined
this[promiseValue] = undefined;
//初始化作业队列
this[thenables] = [];
this[catchables] = [];
/**
* executor 为new Promise(executor)传递进来的函数
* 1.要同步执行,所在构造器函数里面要调用一次。
* 2.executor有两个参数,resolve和reject也是函数,所以这个要写两个函数
*/
/**
* resolve有改变状态的能力
* 由于要改变状态和状态数据,所以要用this,
* 但是外面是直接调用resolve,this指向全局
* 所以这里用箭头函数方便点
* 然后分析reject函数也是如此,所以写个函数
* @param {*} data 状态数据
*/
const resolve = (data) => {
this[changeStatus](data, RESOLVED, this[thenables]);
};
/**
* reject也有改变状态的能力
* @param {*} error 状态数据
*/
const reject = (error) => {
this[changeStatus](error, REJECTED, this[catchables]);
}
/**
* 调用executor函数,执行同步代码
* 如果这里抛出错误就要推向rejected状态
* 所以要捕获错误,然后推向rejected
* */
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
/**
* 改变状态的函数
* @param {*} data 状态数据
* @param {*} status 状态
* @param {*} queue 执行的作业队列
*/
[changeStatus](data, status, queue) {
//状态不可逆或者说只有在pending状态下才能推向resolved或rejected
if (this[promiseStatus] !== PENDING) {
// 如果不是pending直接结束
return;
}
// 是pending才推向后续状态
this[promiseStatus] = status;
this[promiseValue] = data;
//状态改变了 要运行作业队列
queue.forEach((handle) => handle(data));
}
/**
* 后续处理函数
* @param {*} handle 后续处理函数
* @param {*} immediatelyStatus 状态
* @param {*} queue 作业队列
*/
[settleHandle](handle, immediatelyStatus, queue) {
//handle 不是一个函数直接返回
if (typeof handle !== 'function') {
return;
}
if (this[promiseStatus] === immediatelyStatus) {
setTimeout(() => {
handle(this[promiseValue]);
})
} else {
queue.push(handle);
}
}
[linkPromise](thenable, catchable) {
return new MyPromise((resolve, reject) => {
this[settleHandle](data => {
try {
const result = thenable(data); // 返回的结果 当前promise的处理结果
resolve(result); //然后返回的promise推向resolved状态
} catch (err) {
//出了问题才推向rejected
reject(err);
}
}, RESOLVED, this[thenables]);
this[settleHandle](err => {
try {
const result = catchable(err); // 返回的结果 当前promise的处理结果
resolve(result); //然后返回的promise推向resolved状态
} catch (err) {
reject(err);
}
}, REJECTED, this[catchables]);
})
}
then(thenable, catchable) {
//调用then方法传递一个函数,或者两个函数
//如果状态是resolved那么立即执行
//如果不是resolved那么就加入到作业队列里面,等到是resolved才执行
//reject也是同样的处理
//状态是resolved那么立即执行
// if (this[promiseStatus] === RESOLVED) {
// //由于是异步执行,并且真实的效果是放在微队列里面的,而在浏览器环境中没有办法放入微队列里面,
// //所以这里采用setTimeout来模拟,放入到宏任务里面
// setTimeout(() => {
// //将数据传给他,然后外面调用的函数中的data才有值
// thenable(this[promiseValue]);
// })
// } else {
// // 不是resolved那么就加入到作业队列里面
// this[thenables].push(thenable);
// }
// this.catch(catchable);
// this[settleHandle](thenable, RESOLVED, this[thenables]);
// this.catch(catchable);
// 调用then要返回一个promise
return this[linkPromise](thenable, catchable);
}
catch (catchable) {
// this[settleHandle](catchable, REJECTED, this[catchables]);
return this[linkPromise](thenable, catchable);
}
}
})();