与es6的不期而遇 - 异步编程

简单介绍

我们书写的 js 代码,正常的来说,由于 js 的单线程机制, 程序都是自上而下,一步一步的执行,下一行代码必须要等上一行代码执行完毕, 如果上一行代码出 error 了, 下面的代码不会再执行了,这也称作同步编程,当然了,除了同步,自然而然还有一个异步编程,这个异步编程就不是按照代码的先后顺序执行,所以它的执行效率更高,(node.js 里面就充斥了大量的异步代码),但是有一个问题,因为我们下一行的代码可能依赖上一行代码的计算结果,如果没有了先后顺序,那么程序就出 bug 了。接下来我们就来看看异步编程的一些解决方案。

异步编程的应用场景

1 setTimeout
我们常用的定时器,定时器里面的函数总是在同步的代码执行完成之后再执行, 我们来看一个例子

let a = 1;
let b = 0;
setTimeout(() => {
  b = 1;
  console.log("a的值变化:", a);
  console.log("b的值变化:", b);
});
a = 3;
console.log("a的值:", a);
console.log("b的值:", b);

在这里插入图片描述
可以看到,setTimeout里面的回调函数是等到console.log(“b的值:”, b) 这行代码执行完成之后再去执行的, 所以a 的值变成了3,由于b 的值在回调函数里面才改变,所以外层打印的b 的值还是0。所以记住setTimeout 是在程序的最后才执行的就行了。

2 Promise
当你发出 http 请求的时候, 这是一个异步的过程, 因为你不知道后端处理这个 http 请求需要多久,在 ajax 中, 我们通过success 或 error 的回调函数去处理下一步的逻辑,这里就不提了,现在大部分都是用 axios 来处理 http 请求了,这个 axios 是一个基于 Promise 的 Http 库,这里需要提的就是 es6 的 Promise, 这是一个新的对象, 我们来看例子。

let a = 1;
const pp = new Promise((resolve, reject) => {
  // 这里都是同步的代码
  console.log("a的值", a);
  if (a == 1) {
    resolve(a);
  } else {
    reject(a);
  }
});
// 下方的代码就是异步的了
pp.then((res) => {
  console.log("a的值变化", a);
  console.log("res", res);
}).catch((err) => console.log("err:", err));
a = 2;

在这里插入图片描述
第一个要表述的就是这里new Promise 的时候, 相当于初始化这个对象,别看里面写的是回调函数的形式,其实里面都是同步执行的, 我再最后修改了 a 的值, 但是第一次打印a 的值的时候, a还是1, 所以没有变化。
第二个要表述的就是,这里 resolve 和 reject 都表示这个Promise最后的结果, Promise 一旦开始就不会停下来,必须要有一个结果, 成功的结果就用resolve 处理一下, 失败就用 reject 处理一下。
第三个要表述的就是在调用’.then’ 的方法时候, 他里面的回调函数就是异步执行的, 你看此时里面a 的打印结果为2, 所以它是最后执行的,我们用 axios 发送的 http 请求,返回的结果就可以看成这个 pp Promise 对象。
第四个要表述的是, 如果是调用了reject, 我们只能用catch 来捕获, 在then 里面是拿不到的, 我们可以修改下a的初始化的值为2

let a = 2;
const pp = new Promise((resolve, reject) => {
  if (a == 1) {
    resolve(a);
  } else {
    reject(a);
  }
});
pp.then((res) => {
  console.log("res", res);
}).catch((err) => console.log("err:", err));

在这里插入图片描述
能看到then 方法里面的日志并没有打印, 因为前面的reject 了, 其实就是失败了,当错误处理了, 所以我们在用Promise 的时候最好在最后再catch 一下。

3 async ··· awiat
async 语法应该是用起来最舒服的了,这个是 es7 才支持的,但是大部分的浏览器最新版本都已经支持了,其实最早还是在 node.js 里面用 async 语法,不需要考虑浏览器的兼容性,后面发现这种写法实在是太嗨了,就逐步往前端上写,然后浏览器兼容性问题就来了,需要借助 babel 和 polify 来转一下代码,搞起来也是麻烦的很,虽然有webpack 等打包工具,配置起来说起来也不是很复杂,可是我就想写几个HTML页面,为什么要搞那么复杂,所以,自然而然 async 就被纳入下一代的 javascript 标准啦,主流的几个浏览器基本都支持了,除了IE那货,当然这个灾难已经退出历史舞台了,不需要再去考虑它了。我们一起来看下代码,为啥说它用起来最舒服,当然是因为它单纯(简单)。

const sum = async (a, b) => {
console.log("async 函数调用了");
return a + b;
};

sum(1, 2).then((res) => {
console.log("结果:", res);
});
console.log("程序运行结束了")

在这里插入图片描述
第一点想说的是这个 async 函数返回的是一个 Promise 对象,return的结果,通过 ‘.then’ 方法调用获取到。这样好像看不出来它高级在哪,接下来看

const numChange = (num) => {
   return new Promise((resolve) => {
     resolve(num * 10);
   });
 };

 const sum = async (a, b) => {
   console.log("async 函数调用了");
   a = await numChange(a);
   console.log("a 改变了:", a);
   b = await numChange(b);
   console.log("b 改变了:", b);
   return a + b;
 };

 sum(1, 2).then((res) => {
   console.log("结果:", res);
 });
 console.log("程序运行结束了");

在这里插入图片描述
第二点要注意的就是async 和 await 连用的时候, await 后面跟着一个 Promise 对象, 程序会等着这个 Promise resolve 结束,再往下执行。 什么意思呢, 我们来分析下,‘a = await numChange(a);’ 这段代码之后, 控制台输出 ‘a 改变了: 10’ , 按照正常异步的逻辑,程序不会等到异步代码执行结束,这里输出的a的值还是为‘1’, 但是现在成了10, 说明numChange 函数返回的Promise 已经执行了resolve方法,通过单词的意思也很好理解, ‘await’ 就是等待一个程序执行完成,再往下执行, 这样异步代码就变成了同步,真的方便很多。await 只能用于async 函数中,不能单独使用,不然会报错, 当然await 后面不一定必须是Promise, 也可以是数字, 字符串等其他js 代码,这就没什么意义,它被设计出来就是解决异步编程问题的。

4 generator
Generator 这个我们称之为生成器,其实应用的并不多,但也是一种异步编程的解决方案,它主要解决的就是回调地狱问题,比如你通过一个userId, 发送一个获取用户信息的请求,然后要根据返回用户的部门ID, 再去获取部门的信息等, 就是一层层的请求嵌套,我们不推荐Promise 请求的嵌套,所以这个generator 就是这个问题的,当然啦,我们有了async await,用起来其实更简单, 用Promise.all 应该也能解决问题, 所以这个生成器我们应用的不广泛,它其实提出了一种流的编程思想,和angular.js 里面大量使用的 rx.js有异曲同工之妙,这里就不过多的介绍了,自己感兴趣的话可以再去了解下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值