Promise : ES6 出来处理异步问题的内置类,用于解决异步的回调地狱问题 ;
要想彻底的整明白promise,首先我们从什么是同步什么是异步开始讲起。
一、同步和异步
同步:
1.从上往下按顺序依次执行
2.只有将一个任务完全执行完后, 才执行后面的
3.会阻塞后面的代码执行
异步:
1.启动任务后, 立即向下继续执行, 等同步代码执行完后才执行回调函数
2.不会阻塞后面的代码执行
3.异步回调函数会即使触发了, 也是要先放入队列中待执行, 只有当同步任务或前面的异步任务执 行完才执行
//同步执行
console.log(111);
function fn(cb) {
setTimeout(() => {
console.log(333);
cb();
});
}
console.log(222)
//异步执行
fn(function(){
console.log("异步之后执行的代码");
})
二、回调函数是ES5里处理异步顺序的解决方案
回调函数会出现一些问题,回调函数容易写成回调地狱
回调地狱 :回调函数出现层层嵌套;(可维护性差,可读性差,代码不够优雅)
function fn(cb) {
setTimeout(() => {
cb();
}, 1000);
}
fn(function () { // 回调地狱 ;
// 标志异步fn函数执行完毕
console.log(111);
fn(function () {
console.log(222);
fn(function () {
console.log(3333);
fn(function () {
console.log(4444);
})
})
})
})
三、回调地狱解决的三种方式?
1.ES6里的 promise
2.async await 解决回调地狱;
3.观察者模式
1.Promise
1.promise的三种状态:
1.pending 没有任何操作
2.resolved/fulfilled 成功的状态
3.rejected 失败的状态
1.没有任何操作 pending :promise对象状态是 pending,值是undefined ;
let p = new Promise(function(resolve,reject){
});
console.log(p);
// [[PromiseState]]:pending ; [[PromiseResult]]:undefined
如图所示:
2.调取 resolve参数 ;fufilled
/*
[[PromiseState]]:fufilled (成功)
[[PromiseResult]]:是 resolve函数里传的参数;
*/
let p = new Promise((resolve,reject)=>{
resolve(456)
})
console.log(p);
var obj = {
myname:"张三"
}
console.log(obj);
setTimeout(() => {
obj.myname = "李四";
},10);
如图所示:
3.失败的状态 rejected
/*
[[PromiseState]]:rejected (失败)
[[PromiseResult]]:是 reject里传的值;
*/
let p = new Promise((res,rej)=>{
rej("err");
})
console.log(p);
如图所示:
2.Promise对象的then方法
每一个promise对象都会有一个then方法
then方法里有2个回调函数,onResolved和onRejected。
1.onResolved: 在调取 resolve函数的时候执行 (then里的第一个回调函数)
promiseState : fufilled 状态的时候
promiseResult: 作为 onResolved函数的参数;
2.onRejected : 在调取reject 函数的时候执行;(then里的第二个回调 函数);
promiseState : rejected 状态的时候
promiseResult: 作为 onRejected函数的参数;
1.onResolved回调函数 参数 是promiseResult的结果值;
代码如下:
/*
调用 resolve 的时候 promiseState 变成 fufilled状态
promiseResult 是传递的参数 success
*/
let p = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve("success");
// reject("错误");
}, 2000);
})
console.log(p);
p.then(function(res){ // 是成功状态的promise对象的promiseResult结果值;
console.log("onResolved执行了",res);
},function(){
console.log("onRejected执行了");
});
结果展示如下:
2.onRejected回调函数
代码如下:
let p = new Promise((resolve,reject)=>{
setTimeout(() => {
// resolve("success");
reject("错误");
}, 2000);
})
console.log(p);
p.then(function(res){ // onResolved 函数
console.log("onResolved",res)
},function(err){ // onRejected函数
console.log("onRejected",err);
})
结果展示如下:
3.promise简单使用
1.通过回调函数解决异步执行顺序问题
function fn(cb){
setTimeout(() => {
console.log("fn函数执行了");
cb();
}, 2000);
}
fn(function(){
console.log("异步函数执行之后在执行的代码");
});
2.通过promise 来解决异步函数的执行顺序问题;
function fn() {
let p = new Promise(resolve => {
setTimeout(() => {
console.log("fn函数执行了");
resolve("success");
// 函数执行完毕之后执行resolve方法
}, 2000);
})
return p; // 返还promise对象;
}
fn().then(function(res){
console.log("异步函数执行之后在执行的代码",res);
},function(err){
console.log(err);
})
4.then的返还值
既然已经会简单使用promise,那我们进一步了解then的返还值。
它一共有四种情况,代码如下:
- 如果then 的 onResolved 和 onRejected里没有任何返还;
// then会返还一个
//promiseState: fufilled promiseResult:undefined
// 无论调取的是 resolve 还是reject 都是一个成功状态promise对象;
let p = new Promise((resolve, reject) => {
resolve("success");
reject("err");
})
let p2 = p.then(function (res) {
console.log(res)
}, function (err) {
console.log(err);
});
console.log(p2);
2.如果then的onResolved和onRejected 里有普通的返还值
// then的返还值 是一个fufilled状态的promise对象,promiseResult就是返还的内容
// 无论是调取的resolve 还是reject 都会是一个fufilled状态promise对象 promiseResult就是返还的内容;
let p2 = p.then(function (res) {
console.log(res)
return 1111;
}, function (err) {
console.log(err);
return 2222;
});
console.log(p2);
打印如下:
3.在then的 onResolved 及onRejected 里返还一个promise对象
会把 onResolved 及onRejected 里返还的promise对象原封不动返还出来
(1)then的 onResolved
let p = new Promise((resolve, reject) => {
resolve("success"); //如果是onResolved
// reject("err");
})
let p2 = p.then(function (res) {
console.log(res)
return new Promise(resolve=>{
resolve(1111);
});
}, function (err) {
console.log(err);
return new Promise(resolve=>{
resolve(222);
});
});
console.log(p2);
(2)在then的 onRejected
let p = new Promise((resolve, reject) => {
// resolve("success");
reject("err"); //如果是onRejected
})
let p2 = p.then(function (res) {
console.log(res)
return new Promise(resolve=>{
resolve(1111);
});
}, function (err) {
console.log(err);
return new Promise(resolve=>{
resolve(222);
});
});
console.log(p2);
4.在then的onResolved 及onRejected 抛出了错误,那么then的返还值就得到一个 rejected状态的promise对象
let p = new Promise((resolve, reject) => {
// resolve("success");
reject("err");
})
let p2 = p.then(function (res) {
console.log(res)
throw new Error("错了");
}, function (err) {
console.log(err);
throw new Error("错了222");
});
console.log(p2);
打印结果如图:
以上就是then的四种返还值情况。
5. then的链式调用
上一章我们了解了then的返还值:
1.回调没返还 promise对象
2.返还普通值 promise对象
3.返还promise对象 ,原封不动的返还promise对象
4.抛出错误 返还一个失败状态的promise对象;
由此可以得出:
无论如何 then的返还值 都是一个promise对象,每个promise对象都会有then方法;
我们可以进一步掌握then的链式调用,如下:
1.无限链式调用
let p = new Promise(res=>{
res(11);
})
let p2 = p.then(res=>{ // p2 是promise对象
console.log(res);
// return 222
return new Promise(res=>{
res(333);
})
},err=>{
console.log(err)
})
p2.then(res=>{
console.log(res)
},err=>{
})
2.链式的使用 ;依次让异步执行;
// 链式的使用 ;依次让异步执行;
function fn1() {
return new Promise(reslove => {
setTimeout(() => {
console.log(111);
reslove();
}, 1000);
})
}
function fn2() {
return new Promise(resolve => {
setTimeout(() => {
console.log(222)
// cb();
resolve();
}, 1000);
})
}
function fn3() {
return new Promise(resolve => {
setTimeout(() => {
console.log(333)
resolve();
}, 1000);
})
}
// then的链式调用
fn1().then(() => {
console.log("第一个执行完毕");
// fn2().then(()=>{
// })
return fn2();
}).then(() => {
console.log("第二个执行完毕");
return fn3();
}).then(()=>{
console.log("第三个执行完毕");
})
6.then的穿透
在then里的回调函数,无论是 onResolved 还是 onRejected 回调函数,只要传入的参数 不是函数,那么 then就会出现穿透现象。会把之前的promise对象原封不动的返还回来;
let p = new Promise((resolve,reject)=>{
// resolve("1111");
reject(222);
})
p.then(res=>{ // 正常写法
},err=>{
console.log(err);
})
7.then是异步的
根据刚开始我们讲到同步是依次执行,异步是同步代码执行完后才执行回调函数。
我们用代码来证明then是同步还是异步。
console.log(111);
setTimeout(() => {
console.log(222)
});
let p = new Promise(reslove=>{
console.log(333);
reslove();
})
p.then(()=>{
console.log(444)
})
console.log(555)
输出结果为111-333-555- 444-222
我们可以看出444和222都为异步,为什么4在2的前面呢?
8.微任务和宏任务
接下来讲到异步中的微任务和宏任务。
微任务:可以插队,promise里的then就是微任务 ,颗粒度更小 (精度更高)
提高任务的响应精度;
微任务队列 : 【1】【2】【3】【4】【5】【6】
| 【7(需要立刻响应的任务)】
宏任务 :有定时器 ,网络请求,资源加载(其他基本都是宏任务) (颗粒度大,精度差)
宏任务一定需要排序执行不能插队,精度随机
[1][2][3][4][5][6]
[7]
执行顺序 :会先执行宏任务 ,在执行宏任务后的微任务队列
(表现上是微任务先执行;)
9.promise的实例方法
1.catch:
1.捕捉错误 是 onRejected的别名 ,异步微任务,返还值和onRejected一样。
2.捕获then链式上的错误 。 后期写then的时候写一个回调后面在加上一个catch就可以了;
// promise的实例方法
let p = new Promise((resolve, reject) => {
// resolve(111);
reject("error");
})
// catch返还值 和 onRejected 回调返还值一样;
// catch 也是异步的 ,也是微任务;
console.log(111);
let p2 = p.then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
return 111;
})
console.log(p2);
console.log(222);
catch 可以捕捉 then链式上的错误;
let p = new Promise((resolve, reject) => {
resolve(111);
reject("error");
})
function fn1() {
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000);
})
return p1;
}
function fn2() {
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222);
// reject("第二个错误了");
}, 1000);
})
return p2;
}
function fn3() {
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(333);
reject("第三个错误了");
}, 1000);
})
return p3;
}
fn1().then(res=>{
console.log(res);
return fn2();
}).then(res=>{
console.log(res);
return fn3();
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log("catch",err);
})
2.finally :最后
promise执行完毕(成功、失败)之后 调用finally里的回调函数;
finally 里的回调函数没有参数;
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
// resolve("success");
reject("err");
},2000)
})
p.then(res=>{
console.log(res);
}).finally(()=>{
console.log("会在promise执行完毕之后调用");
})
3.all
Promise.all([p1, p2, p3])
接收包含多个promise的数组, 返回一个新的promise
只有当所有接收的promise都成功了, 返回的promise才成功, 且成功的value为所有成功promise的value组成的数组
一旦有一个失败了, 返回的promise就失败了, 且失败的reason就是失败promise的reason
4.race
Promise.race([p1, p2, p3])
接收包含多个promise的数组, 返回一个新的promise
返回的promise的结果由第一个完成的promise决定
2.async 和 await
ES8: async 和 await 是 异步的终极解决方案,是 then的语法糖;
作用: 简化promise对象的使用, 不用再使用then/catch来指定回调函数
注意:
调用async函数得到是一个promise, 其结果状态由async函数体执行的结果决定
await的右侧也可以不是promise, 如果不是, 直接返回表达式的值
一、基本使用
改写了then的链式调用;用同步的写法实现异步调用;
function fn1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 1000);
})
}
function fn2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222)
// reject("22错误了");
}, 1000);
})
}
function fn3() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 1000);
})
}
// 让三个异步函数依次执行 ;
// fn1().then(res=>{ 错误的依次执行;
// console.log(res);
// })
// fn2().then(res=>{
// console.log(res);
// })
// fn3().then(res=>{
// console.log(res);
// })
// async await 改写了 then的调用方式;
// fn1().then(res=>{
// console.log(res);
// return fn2();
// }).then(res=>{
// console.log(res);
// return fn3();
// }).then(res=>{
// console.log(res);
// }).catch(err=>{
// console.log(err);
// })
async function fn() {
let res = await fn1();
console.log(res);
let res2 = await fn2();
console.log(res2);
let res3 = await fn3();
console.log(res3);
}
fn(); // 调用函数;
1.async 及 await 涉及的问题
1.捕捉错误使用try… catch…
注意 catch的写法 和then里catch的写法不同 ;
try {
let res = await fn1();
console.log(res);
let res2 = await fn2();
console.log(res2);
let res3 = await fn3();
console.log(res3);
}catch{
console.log("错了");
}
2.async 和 await 不能出现在嵌套函数里;
3.await 只会等待一个async函数里的异步;
3.观察者模式
未完待续。。。。。
以上就是关于同步,异步及promise的具体使用方法。