Promise
1.解决异步编程的方案:
(1)回调函数:
使用回调函数接受异步任务的执行结果。
缺点:存在回调地狱的问题,必须在启动异步任务之前指定回调函数。
(2)promise:
Promise是异步编程的一种解决方案。Promise对象可以用来封装异步操作,然后保存异步操作的结果。
它不是新的语法功能,只是回调函数的改进,允许将回调函数的嵌套,改成链式调用。
缺点:代码冗余,一大堆的then,原来的语义变得很不清楚。
(3)Generator函数:
通过yield
命令将多个异步任务分开,每调用一次next方法,就执行一个异步任务,并返回异步任务的执行结果。
缺点:需要手动调用next方法
(4)async,await :
Generator的封装,相当于一种语法糖,可以自动调用next方法
2.Promise基础
(1)promise的三种状态:
pendding,resolved,rejected
promise的状态只能从pendding状态变为resolved,rejected状态,不能逆向转变,且只能改变一次。
(2)promise的then方法:
用于指定成功的回调函数和失败的回调函数,用于接收异步任务执行的结果,可以为promise对象指定多个成功和失败的回调函数。
(3)then方法返回的Promise对象的状态和值由什么决定:
then方法会返回一个promise对象,该对象的状态由指定的回调函数的返回值决定:
若没有返回值,则返回的Promise的状态为resolved,值为undefined;
若返回的是一个非promise对象的值,则返回的promise的状态为resolved,值为原返回值;
若抛出的是一个异常,则返回的Promise对象的状态为rejected,值为原错误对象。
若返回的是一个promise对象,则then方法返回的promise状态和值与该promise对象保持一致。
3.回调地狱相关
(1)什么是回调地狱问题:
回调地狱是指同时存在多个异步操作,且后面的异步操作依赖于前面操作的结果,形成了回调函数多层嵌套的情况。
回调函数的缺点:不便于阅读,代码维护较困难。
(2)Promise解决回调地狱的问题:
通过链式调用的方法解决回调地狱的问题
new Promise((res,rej)=>{
setTimeout(()=>{
res(1111)
})
}).then(value=>{
setTimeout(()=>{
res(222)
})
}).then(value=>{
setTimeout(()=>{
res(333)
})
})
(3)Generator函数解决回调地狱的问题:
利用Generator函数的暂停执行的效果,可以把异步操作写在yield语句里面,等到调用next方法时再往后执行。
这样做的好处是不需要通过回调函数来拿到异步操作的执行结果。简化了代码。
缺点:需要手动调用next方法
function* fn(){
yeild 异步任务1;
yeild (function(rs1){return xxx})(rs1) 异步任务2;
}
let fn();
let rs1=fn.next();//返回的是异步任务1的结果
fn.next(rs1);//将异步任务1的结果作为参数传递
(4)async/await解决回调地狱的问题:
async/await是generator的封装,async可以自动执行next方法;
async会返回一个promise对象。该对象的状态由async函数的返回值决定。
async function fn(){
const rs=await fn1();
const rs=await fn2();
}
4.Promise代码相关:
(1)用es6中的类简单的实现一个promise:
class Promise {
constructor(executor) {
this.state = "pendding";
this.data = undefined;
this.callBack = [];
executor(this.resolve.bind(this), this.reject.bind(this));
}
resolve(data) {
if (this.state != "pendding") {
return;
}
this.state = "resolved";
this.data = data;
const that = this;
if (this.callBack.length > 0) {
setTimeout(() => {
that.callBack.forEach((item) => {
item.onResolved(that.data);
});
});
}
}
reject(reason) {
if (this.state != "pendding") {
return;
}
this.state = "rejected";
this.data = reason;
const that = this;
if (that.callBack.length > 0) {
setTimeout(() => {
that.callBack.forEach((item) => {
item.onRejected(that.data);
});
});
}
}
then(onResolved, onRejected) {
if (this.state == "resolved") {
onResolved(this.data);
} else if (this.state == "rejected") {
onRejected(this.data);
} else {
this.callBack.push({
onResolved,
onRejected,
});
}
}
}
new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(222);
reject(333);
}, 1000);
}).then(
(value) => {
console.log(value);
},
(reason) => {
console.log(reason);
}
);
(2)promise封装Ajax请求:
function myAjax(url){
return new Promise((resolve,reject)=>{
const 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)
}
}
}
})
}
const p = myAjax('http://....');
p.then(value=>{
console.log(value);
})
(3)如果已经有三个promise,A、B和C,想串行执行,该怎么写?:
//1.直接利用promise的链式调用
new Promise((res,rej)=>{
return A;
}).then(value=>{
return B;
}).then(value=>{
return C;
})
//2.使用async/await
(async function fn(){
const rs1=await A;
const rs2=await B;
const rs3=await C;
})()
(4)Promise例题:
① 示例1:
setTimeout(() => {
console.log(1);
})
new Promise((resolve, reject) => {
console.log(2);
resolve()
}).then(value => {
console.log(3);
}).then(value => {
console.log(4);
})
console.log(5);
输出:2 5 3 4 1
② 示例2:
const first = () => (new Promise((resolve, reject) => {
console.log(1);
let p = new Promise((resolve, reject) => {
console.log(2);
setTimeout(() => {
console.log(3);
resolve(4)
})
resolve(5)
})
resolve(6)
p.then(value => {
console.log(value);
})
}))
first().then(value => {
console.log(value);
})
console.log(7);
输出:1 2 7 5 6 3
③ ⭐️ 示例3:
setTimeout(() => {
console.log(1);
}, 0);
new Promise((resolve, reject) => {
console.log(2);
resolve()
}).then(value => {
console.log(3);
new Promise((resolve, reject) => {
console.log(4);
resolve()
}).then(value => {
console.log(5);
}).then(value => {
console.log(6);
})
}).then(value => {
console.log(7);
})
new Promise((resolve, reject) => {
console.log(8);
resolve()
}).then(value => {
console.log(9);
})
输出:2 8 3 4 9 5 7 6 1