一、Promise
1.1 回顾回调函数:
1).概念:
一个函数在另一个函数调用(一个函数传递另一个函数做参数使用)
2).异步和同步:
在js,在主线程上面,先执行同步任务,再执行异步任务,等主线程上的同步任务全部完成之后,回到异步队列进行查找,将异步队列里面的任务放到执行栈中,继续遵循规则;
同步:排队执行;
异步:不会阻塞后面代码执行;
1.2 promise
1)概念: 解决异步编程的方法
2)语法: 需要new 实例化;resolve返回的是成功状态值;reject返回的是失败状态值;
接收失败状态的区别:
1. catch直接捕获reject返回的失败状态值;
2.then里面有第二个参数err,捕获就是失败状态值;
区别:使用catch,不仅可以接收reject返回的失败状态值,也可以捕获在成功状态时,处理业务逻辑时报的错;then里面的第二个回调函数来接收;只能捕获reject返回的失败状态的值
3)特点:
1. 三种状态:进行时,已成功,已失败
2. 两种状态转换:进行时=》已成功;进行时=》已失败
4)promise一旦创建就会立即执行(同步任务);
调用resolve或reject执行异步任务;状态也会发生改变:由进行中=》已成功或者是已失败;
console.log(1); let p1 = new Promise((resolve, reject) => { console.log('promise'); // 同步任务 进行中 resolve("success"); }); p1.then(res => { console.log(res) // 异步任务 微任务 }); console.log(2); // 最终打印出的结果先后顺序为 1, promise, 2, success
5)链式调用:从第二个then开始,拿的是上一个then return之后的返回值;
案例1:
function fn(num) { return new Promise(resolve => { setTimeout(() => { resolve(num) }, 1000); }); }; console.log(fn()); fn(10).then(res => { console.log(res) return fn(++res) }).then(res => { console.log(res) return fn(++res) }).then(res => { console.log(res) });
6)解决回调地狱:
ajax请求成功与失败结果与promise本身的成功与失败的状态没有必然的联系
function myAjax({ type = "get", url, data = {} }) { return new Promise((resolve, reject) => { $.ajax({ type, url, data, success: function(response) { resolve(response.result.data); } }) }); };
7)Promise.all 和 Promise.race
Promise.all() 做并发处理,等所有的请求有了返回值之后,同一返回,返回的是一个数组;
Promise.race() 获取的是请求速度最快的值;(设置定请求时间,超过500ms的时候,提示用户请求超时。)
let p1 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('123'); },5000); }); let p2 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('456'); // reject('error'); },1000); }).catch(err=>{ console.log(err); }) ; Promise.all([p1,p2]).then(res=>{ console.log(res); // ["123", "456"] 等5s后才会打印出 }); Promise.race([p1,p2]).then(res=>{ console.log(res); // 456 });
错误捕获两种方法:
直接在all方法后面直接写catch;只返回失败状态值,其他请求成功状态的值,无法返回;
谁返回的失败状态,谁来处理;既可以接收本身自己的失败状态值,其他请求成功状态的值,也不受影响
二、async函数:
1.Async 函数是Generator函数语法糖;
2.语法:
1) 在function前面加async关键字;
箭头函数async关键字放在形参的前面;
2) 返回的是一个promise对象;
3) await 等待:
1.await后面的值,不会返回到函数的外部;
2.async函数内可以有多个await
3.await等待的是后面表达式的结果值;注意,如果是promise对象,默认情况下只返回成功状态值;
4.await有阻塞后面代码执行作用,await后面的表达式有结果之后,下面的代码才可以执行;
5.async函数内部是同步任务;不影响主线程上任务的执行顺序;
let p1 = new Promise(resolve => { setTimeout(() => { resolve("p1") }, 3000); }); console.log("fn start"); async function fn() { console.log(1); let a = await p1; console.log(a); console.log(2); }; console.log("fn end"); fn();
4) 捕获错误信息:
- 直接使用catch
- Try...catch
- 优雅封装方法:
let p1 = new Promise((resolve, reject) => { if (true) { resolve("success") } else { reject("失败") }; }); // promise自己调用catch方法 // async function fn() { // let a = await p1.catch(err => { // console.log(err) // }); // console.log(a); // }; // fn(); // try...catch // async function fn() { // try { // let a = await p1; // console.log(a) // } catch (error) { // console.log(error) // }; // }; // fn(); // 优雅捕获错误 function to(promise) { return promise.then(res => [null, res]).catch(err => [err,undefined]); }; async function fn() { let [err, data] = await to(p1); console.log(err, data); }; fn();
5) 解决回调地狱:
案例1:1秒打印一个1:
function fn2() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }) } async function fn3() { let a = await fn2(); console.log(a); let b = await fn2(); console.log(b); let c = await fn2(); console.log(c); let d = await fn2(); console.log(d); } fn3();
案例2:ajax封装
function myAjax({ type = "get", url, data = {} }) { return new Promise(resolve => { $.ajax({ type, url, data, dataType: "jsonp", success: function(response) { resolve(response); } }) }); };