js是单线程的,前端的并发指的是:在极短时间内发送多个数据请求,比如说循环中发送ajax
总结:推荐使用 axios来发送 ajax请求
- 支持 node环境和浏览器环境
- 提供支持并发的api,如axios.all、axios.spread
- 这些api考虑到的边界条件、兼容性肯定是比原生方法好用的
- 如果用原生的 Promise,推荐使用:Promise.allSettled
async & await
async函数其实就是generator + promise的语法糖
koa2 可以在node环境中使用async、await语法,所以在koa2中很推崇使用async、await来处理异步
const getData1 = () =>new Promise((resolve, reject) => {setTimeout(() => resolve([1, 2, 3]), 1000);});const getData2 = () =>new Promise((resolve, reject) => {setTimeout(() => resolve([4, 5, 6]), 2000);});const useAsync = async () => {console.time(); // 开始计时// 直接 await会阻塞队列,总的执行时间是两个请求加起来的时间;最终能拿到两个异步的值,看下面的优化// const data1 = await getData1(); // 直接 await会阻塞// const data2 = await getData2();// console.timeEnd(); // default: 3008.10400390625 ms// await优化,**一行代码判断是否掌握 async的原理**const p1 = getData1();const p2 = getData2();// 处理并发不阻塞的 await语法const data1 = await p1;const data2 = await p2;console.timeEnd(); // default: 2008.10400390625 msconsole.log(data1, data2); // (3) [1, 2, 3] (3) [4, 5, 6]}useAsync();
Promise.all
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Promise的特点
- Promise构造函数是同步的,promise.then()中的函数是异步的
- Promise只能从pending->resolve 或pending->reject,状态一但改变就不能再变
- Promise.then、Promise.catch中不能return promise对象本身
- Promise.then中必须是函数
用Promise.all处理并发:
- 当所有promise全部成功时, 会走.then,并且可以拿到所有promise中传进resolve中的值
- 其中有一个promise执行失败, 不会走.then, 会走finally,finally不管成功失败都会执行
- 如果其中有一个 Promise走Preject,不能获取到其它 resolve的传递过来的值
- 因为finally回调函数中,无参数,所有拿不到执行成功的promise传进resolve的值
console.time(); // 开始计时Promise.all([p1, p2]).then(result => {// 有一个请求失败,不会执行到这里,直接走 finallyconsole.timeEnd();console.log(result);}).finally(() => {console.timeEnd(); // 计时结束 default: 3000.71923828125 ms})
Promise.allSettled
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
Promise.allSettled在处理并发时,不怕异步执行失败,继续会走.then
- 其中有一个promise执行失败时,会继续走.then, 并且可以同时拿到传给resolve、reject的值
- 完美解决promise.all在并发有失败情况下,拿不到值的情况
console.time(); // 开始计时Promise.allSettled([p1, p2]).then(result => {console.timeEnd();console.log(result); // [{…}, {…}]/* status可以拿到promis执行状态, value、reason 分别可以拿到执行成功和执行失败传过去的值0: {status: "fulfilled", value: Array(1)}1: {status: "rejected", reason: Array(1)}*/})
缺点,比起promise.all兼容性差一点,多了两个不支持的浏览器
安卓端火狐浏览器 Firefox for Android
Samsung Internet 浏览器
