promise
promise的三种状态
1.pending 等待
2.fulfilled 完成
3.rejected 拒绝
1.promise的原型方法
1) then()
2) catch()
3) finally()
then()里面有两个参数为回调函数,第一个参数取resolve的值,第二个参数取reject的值
//方式一:
var p = new Promise(function (resolve, reject) {
resolve('ok');
//reject('no');
//resolve和reject只能二选一
});
//then(),取得resolve或者reject的结果
p.then(function (res) {
console.log('resolve:' + res);//第一个函数取resolve的值
}, function (res) {
console.log('reject:' + res);//第二个函数取reject的值
});
//方式二:
var p = new Promise(function (resolve, reject) {
//resolve('ok');
reject('no');
})
p.then(function (res) {
console.log(res);
}).catch(function (res) {
console.log(res);//异常捕获,当reject时执行
}).finally(function () {
console.log(res);//始终执行,不管是resolve还是reject
});
then执行成功的回调
var promise = new Promise((resolve, reject) => {
resolve('成功') // 成功的函数调用,在调用的时候可以传递对应的参数
})
promise.then((res) => {//接收resolve传递的参数
console.log('第1次then', res);
return 'hi~'
})
.then((res) => {//接收resolve传递的参数
console.log('第2次then', res);
return 'world'
})
.then() //会发生值穿透
.then((res) => {//接收resolve传递的参数
console.log('第3次then', res);
})
catch执行失败
var promise = new Promise((resolve, reject) => {
reject('失败')
})
// catch默认只执行第一个 如果需要往下走,需要手动报错
promise.catch((error) => {//接收reject传递的参数
console.log('第1次catch', error);
throw new Error('失败了') //手动抛出异常
})
.catch((error) => {//接收reject传递的参数
console.log('第2次catch', error);
throw new Error('失败了')
})
.catch() //会发生值穿透
.catch((error) => {//接收reject传递的参数
console.log('第n次catch', error);
})
2.promise的静态方法
1.all
2.race
3.reject
4.resolve
5.allSettled
//静态方法 all
function getDataA(){
return new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('getDataA');
},1000)
})
}
function getDataB(){
return new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('getDataB');
},3000)
})
}
// 方式一:
var arr=[];
getDataA().then(function(res){
arr.push(res);
});
getDataB().then(function(res){
arr.push(res);;
console.log(arr);
})
// 方式二: 利用promise的静态方法 all
Promise.all([getDataA(),getDataB()]).then(function(res){
console.log(res);
})
//静态方法 race
Promise.race([getDataA(),getDataB()]).then(function(res){
console.log(res); //getDataA
});
// 静态方法 Promise.方法名
// 返回成功状态的promis
var promise1 = Promise.resolve('hello')
console.log(promise1); //fulfilled
// 返回失败状态的promise
var promise2 = Promise.reject('错误')
console.log(promise2); //rejected
// all
// 传入一个promise数组 并且执行promise数组里面的promise(如果有一个reject 就为reject)
var promise3 = Promise.reject('错误')
var promise4 = Promise.resolve('hello')
var promise5 = Promise.resolve('1')
var promise6 = Promise.resolve('你好')
var promise7 = Promise.all([promise3, promise4, promise5, promise6])
console.log(promise7);
//传入一个promise数组 不会相互影响 返回所有结果(状态全部为成功)
var promise8 = Promise.allSettled([promise3, promise4, promise5, promise6])
console.log(promise8);
// 返回最快执行完的promise
var promise9 = Promise.race([promise3, promise4, promise5, promise6])
console.log(promise9);
promise的三种状态图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yhpKwMuk-1666795960808)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20221026161135145.png)]
trycatch
try{}catch(error){} //用于捕获异常,网络连接
回调地狱
概述:回调函数的无限嵌套(不会报错),失去了维护价值和代码的可读性
示例
//传入一个函数作为回调函数 在对应代码执行完成调用
function fn1(fn) {
setTimeout(function () {
console.log('10');
//走完了以后回调函数执行
fn()
}, 1000)
}
fn1(() => {
console.log(1);
})
//多个回调函数嵌套 回调地狱 (回调函数的无限嵌套 代码的可读性 可维护性 已经失去了)
fn(() => {
console.log(1);
fn(() => {
console.log(2);
fn(() => {
console.log(3);
fn(() => {
console.log(4);
fn(() => {
console.log(5);
fn(() => {
console.log(6);
....
})
})
})
})
})
})
promise来解决回调地狱(链式调用)
在.then里面返回一个新的promise对象,在对应的异步代码执行完后调用resolve
// promise解决回调地狱
new Promise((resolve, reject) => {
setTimeout(() => {
console.log(1);
resolve()
}, 3000)
}).then(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(2);
resolve()
}, 2000)
})
}).then(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(3);
resolve()
})
})
}).then(() => {
console.log(4);
})
async和await
概述:async和await是对应的两个连用的关键字,async是修饰函数的,await 是修饰promise的。await只能在async内使用。async修饰的函数返回一个promise对象,await修饰的promise对象会占用当前的线程,直到对应的promise执行完成才会释放。
async function fn() {
await new Promise((resolve, reject) => {
// 如果没有放行,后面的代码不会执行
setTimeout(() => {
console.log('hello');
resolve()
})
})
console.log('world');
}
// async修饰函数执行会返回一个promise对象
console.log(fn());
// async修饰的函数返回的promise对象
// 里面的报错 会使当前的promise对象的状态为rejected
// 如果里面return内容 会传递给对应的then
async function fn1() {
// throw new Error('错误')
return '我是美女子'
}
fn1().then(res => {
console.log(res);
}, (error) => {
console.log(error);
})
// await会使用当前的函数的线程占用 直到对应的修饰的promise执行完成
// await Promise.reject() 报错
利用async和await来解决回调地狱
function fn(v, delay) {
return new Promise((resolve, reject) => {
// 如果没有放行,后面的代码不会执行
setTimeout(() => {
console.log(v);
resolve()
}, delay)
})
}
async function fn1() {
await fn(1, 1000)
await fn(2, 3000)
await fn(3, 100)
await fn(4, 0)
console.log(5);
}
fn1() // 1 2 3 4 5
总结
- async修饰函数的
- await修饰promise对象
- async里面使用await 那么如果这个await修饰的promise没有执行完,那么对应的async修饰的函数返回promise状态时为pending。
- 如果async修饰的函数内什么都没有那么对应返回的promise状态是成功(默认函数返回undefined)
- async修饰的函数 返回值就是成功 返回的值传递给then方法
- async修饰的函数如果里面报错 那么返回的是失败 传递的值为报的错
- await只能在async里面使用 await会使当前的函数陷入等待
3、同步、异步
//promise是构造函数,需要new,它本身是同步的,then和catch还有finally是异步的
//promise微任务
console.log(111);
var p = new Promise(function (resolve, reject) {
resolve('ok');
console.log(222);
});
console.log(333);
p.then(function (res) {
console.log(res);
console.log(444);
}).finally(function () {
console.log(555);
});
console.log(666);
//执行结果为: 111,222,333,666,444,555
宏任务: settimeout,setinterval,script标签,事件(onclick,readystatechange...)
微任务: promise.then,promise.catch,nextTick
执行顺序: 先同步,再异步==>异步(宏任务..微任务..微任务,下一个宏任务..微任务..微任务..)
promise解决异步的两种方式:
function getData1(url){
return new Promise(function(resolve,reject){
setTimeout(function(){
var data={code:1,msg:'ok',data:[11,22,33]};
resolve(data);
})
})
}
//方式一: promise + then()
getData1('xxxx').then(function(res){
console.log(res);
return getData1('xxxx');
}).then(function(res){
console.log(res);
return getData1('xxxx');
}).then(function(res){
console.log(res);
});
//方式二: promise + async + await
async function getters(){
const res1 =await getData1('xxxx');
console.log(res1);
const res2 =await getData1('xxxx');
console.log(res2);
const res3 =await getData1('xxxx');
console.log(res3);
};
getters();
防抖(在规定时间内只执行一次 执行最后一次)
//第一个参数是做的操作 第二个参数是等待时间
function debounce(fn,delay){
var timer = null
return function(){
clearTimeout(timer);//清除上一次的等待
//开始新的等待
timer = setTimeout(fn,delay)
}
}
// 调用
btns[0].onclick = debounce(() => {
console.log('防抖');
},1000)
节流 (在规定时间内执行第一次 减少执行次数)
//操作 执行一次的时长
function throttle(fn,delay){
var timer = null
return function(){
// 判断上一次是否已经走完,如果没走完就不执行下面的代码
if(timer){
return
}
// 上一次走完了就开始下一次
timer = setTimeout(()=>{
fn()
timer = null; //走完了要将节流阀设置为false
},delay)
}
}
// 调用
btns[1].onclick = throttle(() => {
console.log('节流');
}, 1000)
防抖和节流的区别
- 防抖执行最后一次 节流执行第一次
- 防抖在规定时间内只会执行一次,节流是在规定时间内减少对应的执行次数
- 防抖开始下一次需要先清除上一次,节流开始下一次要先判断上一次是否执行完毕
函数的柯里化(将多个参数的函数拆分为多个单参数的函数 可以自由组合)
示例
function sum(a,b){
return a + b
}
sum(1,2) //3
简单的函数柯里化
function sum(a){
return function(b){
return function(c){
return a + b + c
}
}
}
console.log(`sum(1)(2)(3)`, sum(1)(2)(3));//6
console.log(`sum(1)(2)`, sum(1)(2));//fn
柯里化核心:参数没够返回对应的函数,参数够了返回对应的结果
//传递一个函数 (参数没到返回函数 参数到了返回结果)
function currying(fn) {
//获取currying传递的参数
let args = Array.prototype.slice.call(arguments,1)
return function () {
//将对应的函数的参数和curry传递参数做连接
let arg = Array.from(arguments).concat(args)
//判断参数个数是否一样
if(arg.length < fn.length){
//参数没到返回函数
return currying.call(this,fn,...arg)
}else{
//参数到了 调用方法返回结果
return fn.apply(this,arg)
}
}
}
调用
function sum(a,b,c){
return a+b+c
}
console.log(`sum(1,2,3)`, sum(1,2,3));
let fn = currying(sum)
console.log(`fn(2)`, fn(2));//函数
console.log(`fn(2)(3)`, fn(2)(3));//函数
console.log(`fn(2)(3)(1)`, fn(2)(3)(1));//6
console.log(` fn()()()(2)()()(3)()()()(1)`, fn()()()(2)()()(3)()()()(10));//15
//参数没到返回函数
return currying.call(this,fn,...arg)
}else{
//参数到了 调用方法返回结果
return fn.apply(this,arg)
}
}
}
调用
```js
function sum(a,b,c){
return a+b+c
}
console.log(`sum(1,2,3)`, sum(1,2,3));
let fn = currying(sum)
console.log(`fn(2)`, fn(2));//函数
console.log(`fn(2)(3)`, fn(2)(3));//函数
console.log(`fn(2)(3)(1)`, fn(2)(3)(1));//6
console.log(` fn()()()(2)()()(3)()()()(1)`, fn()()()(2)()()(3)()()()(10));//15