Promise
1.1、区别实例对象与函数对象
1.实例对象: new函数产生的对象,称为实例对象,简称为对象
2.函数对象:将函数作为对象使用时,简称为函数对象
function Fn(){//Fn函数 }; let fn = new Fn();//Fn是构造函数、fn是实例对象(简称为对象) console.log(Fn.prototype);//Fn是函数对象 Fn.bind({});//Fn是函数对象 $("#test");//jQuery 函数 $.get("/test");//jQuery函数对象
1.2、两种类型的回调函数
1.2.1、同步回调
1、理解: 立即执行,完全执行完了才结束,不会放入回调队列中
2、例子: 数组遍历相关的回调函数、Promise的 excutor函数
例一、数组遍历相关的回调函数let arr = ["a","b","c"];arr.forEach(r => { //遍历回调函数 console.log("11111");});console.log("222222222");例二、Promise的 excutor函数new Promise(resolve => { console.log("11111");})console.log("222222");
1.2.2、异步回调
1、理解: 不会立即执行,会放入回调队列中将来执行
2、例子: 定时器回调 / ajax回调 / Promise的成功|失败的回调
例一、定时器回调setTimeout(() =>{ console.log("11111");}, 0);console.log("222222222");例二、Promise的成功|失败的回调new Promise(resolve => { resolve("")}).then(res => { console.log("1111");})console.log("222222");
1.3、JS 的 error 处理
1.3.1、错误的类型
1、Error: 所有错误的父类型
2、ReferenceError: 引用的变量不存在
3、TypeError: 数据类型不正确的错误
4、RangeError: 数据值不在其所允许的范围内
5.、SyntaxError: 语法错误
// 1、Error: 所有错误的父类型// 2、ReferenceError: 引用的变量不存在 console.log(a);//ReferenceError: a is not defined console.log("----------");//没有捕获 error,下面的代码不会被执行(这行代码没有被执行)// 3、TypeError: 数据类型不正确的错误 let b; // console.log(b.xxx);//TypeError: Cannot read property 'xxx' of null b = {}; b.xxx();//TypeError: b.xxx is not a function// 4、RangeError: 数据值不在其所允许的范围内 function fn(){ fn(); }; fn();//RangeError: Maximum call stack size exceeded// 5.、SyntaxError: 语法错误 const c = """";//SyntaxError: Unexpected string
1.3.2、错误处理
1、捕获错误:try ... catch
2、抛出错误:throw error
//1、捕获错误:try ... catchtry{ let b; console.log(b.xxx );} catch (error){ console.log(error.message); console.log(error.stack);}console.log("出错之后,通过捕获错误,程序能继续处理");//2、抛出错误:throw errorfunction something(){ if(Date.now()%2 == 1){ console.log("当前时间为奇数,可以执行任务"); something() }else{//如果时间是偶数抛出异常,由调用来处理 throw new Error("当前时间为偶数,无法执行任务"); }}try{ something()} catch(error){ alert(error.message)}
2、Promise的理解与使用
2.1、Promise是什么?
2.1.1、理解
抽象表达
1、promise 是ES6中提供的一个异步编程的新的解决方案(旧的是谁?)
具体表达
1、从语法上来说: Promise是一个构造函数
2、从功能上来说: promise对象用来封装一个异步操作,并可以获取其结果
2.1.2、Promise 状态与状态的改变
Promise对象有三种状态:
待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
已兑现(fulfilled): 意味着操作成功完成。
已拒绝(rejected): 意味着操作失败。
这三种状态的变化途径只有2种:
1、pending 变为 resolved
2、pending 变为 rejected
说明:只有这2种,且一个promise对象只能改变一次
无论变为成功还是失败,都会有一个结果数据
成功的结果数据一般称为value,失败的结果数据一般称为reason
2.1.3、Promise 的基本流程
MDN Promise基本流程图
注意: 如果一个 promise 已经被兑现(fulfilled)或被拒绝(rejected),那么我们也可以说它处于已敲定(settled)状态。您还会听到一个经常跟 promise 一起使用的术语:已决议(resolved),它表示 promise 已经处于已敲定(settled)状态,或者为了匹配另一个 promise 的状态被"锁定"了。Domenic Denicola 的 States and fates 中有更多关于 promise 术语的细节可以供您参考。
简化的 Promise基本流程图
2.1.4、Promise 的基本使用
// 1、创建一个新的 Promise 对象 const ret = new Promise((resolve,reject) => {//执行器函数 // 2、执行异步操作任务 setTimeout(() => { const time = Date.now();//如果当前时间是偶数就代表成功,否则代表失败 // 3.1、如果成功了,调用resolve(value) if(time % 2 == 0){ resolve("成功的数据,time=" + time); }else{ // 3.2、如果失败了,调用reject(reason) reject("失败的数据,time=" + time); } }) }) // ret.then( // value => {//接收得到成功的 value 数据 // console.log("成功的回调-----------", value); // }, // reason => {//接收得到失败的 reason 数据 // console.log("失败的回调-----------", reason); // } // ) // promise简化了对error的处理,上面的代码我们也可以这样写: ret.then(//接收得到成功的 value 数据 value => { console.log("成功的回调-----------", value); } ).catch(//接收得到失败的 reason 数据 reason => { console.log("失败的回调-----------", reason); } )
2.2、为什么要使用 Promise?
1. 指定异步回调函数的方式更加灵活:
旧的: 必须在启动异步任务前指定
promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
// 旧的指定回调函数function successBcak(){ console.log("成功的回调");}function failBcak(){ console.log("失败的回调");}function person(age, successBcak, failBcak){ setTimeout(() => { if(age > 0 && age < 100){ successBcak(); }else{ failBcak(); } },1000)}console.log("aaaaaa");person(18, successBcak, failBcak);//在调用前必须指定回调函数,而 Promise不需要console.log("bbbbbbb");// Promiseconst p = new Promise((resolve, reject) => { console.log('执行 executor同步函数') let time = Date.now(); setTimeout(() => {//Promise可以先执行异步任务,再指定回调函数 if (time % 2 === 0) { console.log("resolve") resolve(time) } else { console.log("reject") reject(time) } }, 2000)})setTimeout(() => { p.then(value => { console.log('value', value) }, reason => { console.log('reason', reason) })}, 3000)console.log("aaaaaaaa");
2、 支持链式调用, 可以解决回调地狱问题
什么是回调地狱? 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调函数执行的条件
回调地狱的缺点? 不便于阅读 / 不便于异常处理
解决方案? promise链式调用
终极解决方案? async/await
回调地狱 $.ajax({ url:"查询用户", success:function(res){ console.log(res) // 将数据渲染到页面上 $.ajax({ url: "查询到课程", success:function(res){ // 获取到了课程内容的数据,渲染到页面上 $.ajax({}) } }) }})promise 处理回调地狱new Promise(function(resolve, reject){ $.ajax({ url:"查询用户", success:function(res){ resolve(res) }, error:function(err){ reject(err) } })}).then(res=>{ console.log(res) return new Promise(function(resolve,rejeect){ $.ajax({ url: "查询到课程", success:function(res1){ // 获取到了文章详细内容的数据,渲染到页面上 resolve(res1) }, error:function(err){ reject(err) } }) })}).then(res=>{ console.log(res) return new Promise(function(resolve,rejeect){ $.ajax({ url: "查询到分数", success:function(res1){ // 获取到了文章详细内容的数据,渲染到页面上 resolve(res1) }, error:function(err){ reject(err) } }) })}).then(res=>{ console.log(res)})封装一下 Promisefunction get(url) { return new Promise((resolve, reject) => { $.ajax({ url: url, success: function (data) { resolve(data); }, error: function (err) { reject(err) } }) });}//调用封装后的方法 get("查询用户") .then((data) => { console.log("用户查询成功~~~:", data) return get("查询到课程); }) .then((data) => { console.log("课程查询成功~~~:", data) return get("查询到分数); }) .then((data) => { console.log("课程成绩查询成功~~~:", data) }).catch((err) => { console.log("出现异常", err) });async function foo() { try { const result = await doSomething(); const newResult = await doSomethingElse(result); const finalResult = await doThirdThing(newResult); console.log(`Got the final result: ${finalResult}`); } catch(error) { failureCallback(error); }}
2.3、如何使用 Promise?(常用的 Promise API)
Promise.all:(promises) =>{}
promises:包含n个promise的数组
重点:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败
Promise.all([p1,p2,......]).then(values => { console.log(values);}).catch(error => { consloe.log(error);})
开发中常用的Promise.all场景,获取两个接口成功的返回值后,再执行下面的操作
function p1(){ return new Promise((resolve) => { setTimeout(() => {//接口一 resolve("p1") },2000) })}function p2(){ return new Promise((resolve,reject) => { setTimeout(() => {//接口二 resolve("p2") },1000) })}Promise.all([p1(),p2()]).then(values =>{ console.log(values)}).catch(error =>{ console.log("err",error);})
Promise.race: (promises) =>{}
promises:包含n个promise的数组
重点:返回一个新的promise,说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态
Promise.race([p1,p2,......]).then(values => { console.log(values);}).catch(error => { consloe.log(error);})
function p1(){ return new Promise((resolve) => { setTimeout(() => { resolve("p1") },1000) }) } function p2(){ return new Promise((resolve,reject) => { setTimeout(() => { reject("p2") },2000) }) } Promise.race([p1(),p2()]).then(values =>{ console.log(values) }).catch(error =>{ console.log("err",error); })
3、async 与 await
MDN文档:
async 函数:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function
await:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await
async await 的作用
简化promise对象的使用:不用再使用then()来指定成功/失败的回调函数以同步编码(沿有回凋函数了)方式实现异步流程
3.1、async 函数
1、函数的返回值为promise对象
2.、promise对象的结果由async函数执行的返回值决定
// async 函数的返回值是一个promise对象async function fn1(){ // 同步 // return 1; // throw 2; // return Promise.resolve(3); // return Promise.reject(4); // 异步 return new Promise((resolve,reject) =>{ setTimeout(()=> { resolve(5) },2000) })}let ret1 = fn1();console.log(ret1);// async 函数的返回值是一个promise对象,所以需要通过.then(()=>{})获取函数的返回值ret1.then(res => { console.log("then", res)}).catch(err =>{ console.log("catch", err)})
3.2、 await表达式
await 操作符用于等待一个 Promise 对象。它只能在异步函数 Promise 中使用
1、await右侧的表达式一般为 promise 对象,但也可以是其它的值
2、如果表达式是promise对象, await 返回的是 promise 成功的值(所以获取 promise 失败的返回值,会使用try{} catch (error) {})
function fn2(){ return new Promise((resolve,reject) => { setTimeout(()=> { // resolve(11111) reject(22222) },2000) })}function fn3(){ return 444444;}async function getResult(){ try { let val = await fn2();//await右侧表达为promise对象,得到的结果就是promise对象成功的value console.log("getResult",val); } catch (error) { console.log("失败的结果",error); } // let val2 = await fn3();///await右侧表达不是promise对象,得到的结果就是它本身 // console.log("val2",val2)}getResult();
async与await配合使用
function fn2(){ return new Promise((resolve,reject) => { setTimeout(()=> { resolve(11111) // reject(22222) },2000) })}async function fn3(){//async 函数的返回值是一个promise对象 return 444444;}async function getResult(){ try { let val = await fn2();//await右侧表达为promise对象,得到的结果就是promise对象成功的value let val2 = await fn3(); console.log("getResult",val); console.log("getResult",val2); } catch (error) { console.log("失败的结果",error); }}getResult();
作者:輪徊傷
链接:https://www.jianshu.com/p/b8f98ee2d99a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。