汽车o2o网站建设,石家庄招标网官方网站,濮阳做网站 汉狮网络,临沂哪里有做网站一. Promise
1. 异步
异步#xff1a;则是将耗时很长的A交付的工作交给系统之后#xff0c;就去继续做B交付的工作#xff0c;等到系统完成了前面的工作之后#xff0c;再通过回调或者事件#xff0c;继续做A剩下的工作。AB工作的完成顺序#xff0c;和交付他们的时间顺…一. Promise
1. 异步
异步则是将耗时很长的A交付的工作交给系统之后就去继续做B交付的工作等到系统完成了前面的工作之后再通过回调或者事件继续做A剩下的工作。AB工作的完成顺序和交付他们的时间顺序无关所以叫“异步”。
2. 回调函数
当一个函数作为参数传入另一个函数中并且它不会立即执行只有当满足一定条件后该函数才可以执行这种函数就称为回调函数。我们熟悉的定时器和Ajax中就存在有回调函数.
scriptsetTimeout(() {console.log(执行了回调函数)}, 3000)
/script这里的回调函数是() {console.log( 执行了回调函数 )}在满足时间3秒后执行。
3. 异步函数
scriptsetTimeout(() {console.log(执行了回调函数)}, 3000)console.log(111)
/script如果按照代码编写的顺序应该先输出“执行了回调函数”再输出“111”。但实际输出为 111 执行了回调函数 这种不阻塞后面任务执行的任务就叫做异步任务。
4. 地狱回调
根据前面可以得出一个结论存在异步任务的代码不能保证能按照顺序执行那如果非要代码顺序执行呢 比如要说一句话语序必须是下面这样的武林要以和为贵要讲武德不要搞窝里斗。 必须要这样操作才能保证顺序正确
scriptsetTimeout(() { //第一层console.log(武林要以和为贵)setTimeout(() { //第二层console.log(要讲武德)setTimeout(() { //第三层console.log(不要搞窝里斗)}, 1000)}, 2000)}, 3000)
/script可以看到代码中的回调函数套回调函数套了3层这种回调函数中嵌套回调函数的情况就叫做回调地狱。 当异步操作想要有顺序时只能在一个异步成功以后的回调函数里面嵌套另一个异步的操作如果嵌套的层数过多就形成了回调地狱 回调地狱就是为是实现代码顺序执行而出现的一种操作它会造成我们的代码可读性非常差后期不好维护。 那该如何解决回调地狱呢使用Promise对象
5. 什么是Promise
Promise是ES6异步编程的一种解决方案(目前最先进的解决方案是async和await的搭配ES8但是它们是基于promise的)从语法上讲Promise是一个对象或者说是构造函数用来封装异步操作并可以获取其成功或失败的结果
6. 为什么要使用Promise
最重要也是最主要的一个场景就是ajax和axios请求。通俗来说由于网速的不同可能得到返回值的时间也是不同的但是下一步要执行的代码依赖于上一次请求返回值这个时候就需要等待结果出来了之后才知道怎么样继续下去.
7. Promise特点
Promise是一个对象对象和函数的区别就是对象可以保存状态函数不可以闭包除外Promise并未剥夺函数 return 的能力因此无需层层传递callback进行回调获取数据Promise代码风格容易理解便于维护Promise多个异步等待合并便于解决
8. 创建Promise
8.1 通过Promise构造函数
script//两个参数分别是resolve和reject。它们是两个函数由JavaScript引擎提供不用自己传参//resolve将Promise对象的状态从“未完成”变为“成功”,在异步操作成功时调用并将异步操作的结果作为参数传递出去//reject将Promise对象的状态从“未完成”变为“失败”, 在异步操作失败时调用并将异步操作报出的错误作为参数传递出去。const myPromise new Promise((resolve, reject) {//setTimeout模拟耗时操作3秒后执行setTimeout(() {//获取随机值范围[0,1)const random Math.random()if (random 0.5) {resolve(成功)} else {reject(失败)}}, 3000)})console.log(output-myPromise, myPromise)//then函数处理Promise的成功状态的回调函数//catch函数处理Promise的失败状态的回调函数myPromise.//res的值为resolve函数的实参值then((res) {console.log(output-res, res)console.log(output-myPromise, myPromise)}).//err的值为reject函数的实参值catch((err) {console.log(output-err, err)console.log(output-myPromise, myPromise)})
/scriptPromise构造函数接受一个函数作为参数该函数的两个参数分别是resolve和reject。它们是两个函数由JavaScript引擎提供不用自己传值。
resolve作用将Promise对象的状态从“未完成”变为“成功”即从 pending 变为 resolved在异步操作成功时调用并将异步操作的结果作为参数传递出去reject作用将Promise对象的状态从“未完成”变为“失败”即从 pending 变为 rejected在异步操作失败时调用并将异步操作报出的错误作为参数传递出去。promise对象的状态不受外界影响 3种状态 pending[待定]初始状态fulfilled[实现]操作成功rejected[被否决]操作失败 当promise状态发生改变就会触发then()里的响应函数处理后续步骤promise状态一经改变不会再变。 一旦状态改变就不会再变 两种状态改变成功或失败 从pending变为fulfilled成功从pending变为rejected失败这两种情况只要发生状态就凝固了不会再变了。
获取用户信息案例
script//定义getUserInfo方法const getUserInfo (userId) {return new Promise((resolve, reject) {//模拟耗时操作setTimeout(() {const random Math.random()if (random 0.5) {const user { id: userId, name: jack, age: 30 }// 如果存在使用resolve方法将Promise状态变为成功态resolve(user)} else {// 如果不存在使用reject方法将Promise状态变为失败态reject(用户不存在)}}, 4000)})}//调用getUserInfo方法getUserInfo(001).//成功回调处理then((res) {console.log(output-获取用户成功用户信息为, res)}).//失败回调处理catch((err) {console.log(output-err, err)})
/script在该案例中使用Promise手动管理异步操作。在getUserInfo函数中创建了一个Promise对象将异步操作封装在其中当异步操作执行成功时使用resolve方法将Promise状态变为成功态并传递用户信息当异步操作执行失败时使用reject方法将Promise状态变为失败态并传递错误信息。使用then方法和catch方法分别处理Promise的状态变化如果Promise状态变为成功态将打印用户信息如果Promise状态变为失败态将打印错误信息。
8.2 通过静态方法创建Promise对象
此方式也称为Promise的自动化管理方式。比如Promise.resolve()可以创建一个状态为成功的Promise对象Promise.reject()可以创建一个状态为失败的Promise对象。
案例1:
script//Promise.resolve()和Promise.reject() 方法创建Promise对象const myPromise1 Promise.resolve(成功)const myPromise2 Promise.reject(失败)myPromise1.then((res) {console.log(output-res, res)})myPromise2.catch((err) {console.log(output-err, err)})
/script案例2:
script// 模拟一个异步操作函数const asyncFn () {return new Promise((resolve, reject) {// 模拟一个异步操作2秒钟后将结果返回setTimeout(() {const random Math.random()if (random 0.5) {resolve(success);} else {reject(fail)}}, 2000)})}// 返回一个已解决的Promise对象并使用函数返回值作为解决结果Promise.resolve(asyncFn()).then((value) {console.log(异步操作执行成功, value)// 在这里处理异步操作执行成功的情况}).catch((error) {console.log(异步操作执行失败, error)// 在这里处理异步操作执行失败的情况})
/script在这个例子中定义了一个asyncFn函数该函数返回一个Promise对象在Promise对象的构造函数中使用setTimeout模拟了一个异步操作。然后我们使用Promise.resolve()方法将异步操作函数的返回值转换成一个自动管理状态的Promise对象。最后在使用Promise.resolve()方法返回的Promise对象上使用then()方法和catch()方法处理异步操作成功或失败的情况。
使用Promise.resolve()方法的好处在于如果被传入的参数本来就是一个Promise对象那么直接返回这个Promise对象如果不是Promise对象会自动转换成Promise对象方便在异步操作逻辑中使用。
8.3 Promise对象的链式操作
script// 模拟一个异步操作函数const myPromise1 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise1成功)} else {reject(myPromise1失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise2 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise2成功)} else {reject(myPromise2失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise3 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise3成功)} else {reject(myPromise3失败)}}, 2000)})}myPromise1().then((res1) {console.log(output-res1,res1)return myPromise2()}).catch((err1) {console.log(output-err1,err1)return myPromise2()}).then((res2) {console.log(output-res2,res2)return myPromise3()}).catch((err2) {console.log(output-err2,err2)return myPromise3()}).then((res3) {console.log(output-res3,res3)}).catch((err3) {console.log(output-err3,err3)})//只有一个catch链条中所有的Promise对象有一个reject被执行那么就直接执行最后的catch回调处理myPromise1().then((res1) {console.log(output-res1,res1)return myPromise2()}).then((res2) {console.log(output-res2,res2)return myPromise3()}).then((res3) {console.log(output-res3,res3)}).catch((err) {console.log(output-err,err)})
/scriptthen()返回一个新的Promise实例所以它可以链式调用 如果返回新的Promise那么下一级.then()会在新的Promise状态改变之后执行
8.4 Promise中断
Promise 的特性就是不能中断。一旦执行无法知道它具体执行到哪里了只知道在 pending最后 resolve 或者 reject 才知道执行完毕。Promise可以通过在流程中使用 throw 来中断流程触发catch操作也可以在某一个节点进行 reject来中断操作它的链式调用的then函数。所以在链式调用的过程中是完全可以实现中断操作的。同步的中断Promise
scriptconst someAsyncFn () {return new Promise(function(resolve, reject) {// 在这里写异步代码setTimeout(() {throw new Error(强行中断抛出异常)const random Math.random()if (random 0.5) {resolve(someAsyncFn异步操作成功)} else {reject(someAsyncFn异步操作失败)}}, 2000)// throw new Error(The promise was interrupted)reject(new Error(The promise was interrupted))})}someAsyncFn().then((res) {console.log(res)}).catch((err) {console.log(err)})
/scriptPromise 封装异步请求中断操作
scriptconst someAsyncFn () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random();if (random 0.5) {resolve(someAsyncFn异步操作成功);} else {reject(someAsyncFn异步操作失败);}}, 4000);});};const timeoutWrapper (p, timeout 2000) {const wait new Promise((resolve, reject) {setTimeout(() {reject(请求超时);}, timeout);});return Promise.race([p, wait]);};timeoutWrapper(someAsyncFn()).then((res) {console.log(res);}).catch((err) {console.log(err);});
/script9. Promise 常用静态方法
9.1 Promise.all() 批量执行
Promise.all([p1, p2, p3])用于将多个Promise实例包装成一个新的Promise实例返回的实例就是普通的Promise它接收一个数组作为参数数组里可以是Promise对象也可以是别的值只有Promise会等待状态改变 当所有的子Promise都完成该Promise完成返回值是全部值的数组 有任何一个失败该Promise失败返回值是第一个失败的子Promise结果
script// 模拟一个异步操作函数const myPromise1 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise1成功)} else {reject(myPromise1失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise2 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise2成功)} else {reject(myPromise2失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise3 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise3成功)} else {reject(myPromise3失败)}}, 2000)})}Promise.all([myPromise1(), myPromise2(), myPromise3()]).then((res) {console.log(all, res)}).catch((err) {console.log(all, err)})
/script9.2 Promise.allSettled() 批量执行
用来确定一组异步操作是否都结束了不管成功或失败包含了”fulfilled“和”rejected“两种情况。 当有多个彼此不依赖的异步任务成功完成时或者总是想知道每个子Promise的结果时通常使用它。 相比之下Promise.all() 更适合彼此相互依赖或者在其中任何一个reject时立即结束。
script// 模拟一个异步操作函数const myPromise1 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise1成功)} else {reject(myPromise1失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise2 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise2成功)} else {reject(myPromise2失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise3 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise3成功)} else {reject(myPromise3失败)}}, 2000)})}Promise.allSettled([myPromise1(), myPromise2(), myPromise3()]).then((res) {console.log(all, res)}).catch((err) {console.log(all, err)})/script对于每个结果对象都有一个 status 字符串。如果它的值为 fulfilled则结果对象上存在一个 value。如果值为 rejected则存在一个 reason 。value或 reason 反映了每个 promise 决议或拒绝的值。
可以发现和all相比allSettled在其中一个Promise返回错误时还可以继续等待结果。并且不管内部的计时器定时多少毫秒它都会等所有结果返回后按照传参传入的顺序返回Promise结果
应用场景 比如用户在页面上面同时填了3干个独立的表单这三个表单分三个接口提交到后端三个接口独立没有顺序依赖这个时候需要等到请求全部完成后给与用户提示表单提交的情况.
面试题 共有四个接口第一个接口是崩溃的但是需要返回所有接口的结果。 这一题如果使用 all那么会直接抛出错误所以必须使用allSettled方法请求数据
script srchttps://unpkg.com/axios/dist/axios.min.js/scriptscriptlet a axios.get(http://xxxa)let b axios.get(http://xxxb)let c axios.get(http://xxxc)let d axios.get(http://xxxd)Promise.allSettled([a, b, c, d]).then((res) {console.log(res)}).catch((err) {console.log(err)})
/script9.3 Promise.race() 批量执行
Promise.race()方法同样是将多个子Promise实例包装成一个新的Promise实例但是只要有一个子Promise 实例状态发生变化就将新的Promise实例的状态改变且终值由第一个完成的 Promise提供。
script// 模拟一个异步操作函数const myPromise1 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise1成功)} else {reject(myPromise1失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise2 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise2成功)} else {reject(myPromise2失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise3 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise3成功)} else {reject(myPromise3失败)}}, 2000)})}Promise.race([myPromise1(), myPromise2(), myPromise3()]).then((res) {console.log(all, res)}).catch((err) {console.log(all, err)})
/script应用场景 Promise.race()方法也有许多实际使用场景。它可以用于处理需要快速获取结果的情况例如当向多个不同的服务器请求同一个资源时可以使用Promise.race()方法来获取最快返回结果的服务器的响应并忽略其他服务器的响应结果。或者在一个Web应用程序中需要在指定的时间内获取用户的同步输入和异步请求结果可以使用Promise.race()方法同时监听用户输入事件和请求结果事件一旦其中有一个事件触发就可以立即返回响应结果提高应用程序的响应速度和用户体验。另外Promise.race()方法还可以用于处理超时情况例如在一个HTTP请求的响应时间超过一定时间后可以使用Promise.race()方法将该请求和一个延迟一定时间的Promise实例包装起来一旦有一个Promise进入fulfilled状态就可以立即返回响应结果。如果请求在规定的时间内仍未返回则将其取消并返回一个错误信息给用户以提高应用程序的可用性和稳定性。
9.4 Promise.any() 批量执行
Promise.any()方法会对多个Promise进行竞争直到有一个子Promise进入Fulfilled状态Promise实例返回该Promise的结果。如果所有Promise都进入Rejected状态则返回失败状态其中维护Promise及其状态的任何提示返回数组都是必需的。 Promise.any()跟Promise.race()方法很像只有一点不同就是Promise.any()不会因为某个Promise 变成rejected状态而结束必须等到所有参数 Promise 变成rejected状态才会结束。
script// 模拟一个异步操作函数const myPromise1 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise1成功)} else {reject(myPromise1失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise2 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise2成功)} else {reject(myPromise2失败)}}, 2000)})}// 模拟一个异步操作函数const myPromise3 () {return new Promise((resolve, reject) {setTimeout(() {const random Math.random()if(random 0.5) {resolve(myPromise3成功)} else {reject(myPromise3失败)}}, 2000)})}Promise.any([myPromise1(), myPromise2(), myPromise3()]).then((res) {console.log(all, res)}).catch((err) {console.log(all, err)})
/script使用场景 Promise.any()方法可以用于处理多种资源竞争的情况例如在一个抢单系统中多个用户需要争夺同一个订单系统将同时向多个用户发送请求并使用Promise.any()方法监听所有请求的状态一旦有一个用户成功抢到订单系统就立即返回订单信息并发送通知给该用户从而提高了用户的参与度和系统的可用性。除此之外Promise.any()方法还可以用于指定默认值或备选方案例如在一个多语言网站中需要从多个API获取多语言翻译结果但有些API可能由于网络原因或其他问题无法正常工作这时候就可以使用Promise.any()方法来一次性向多个API发送请求并设置一个默认值或备选方案一旦有一个API正常返回翻译结果就立即返回结果给用户如果所有API都无法正常工作则返回默认值或备选方案。