Js异步编程Promise和async/await方式总结

Promise简单介绍

Promise 是异步编程的一种解决方案,比传统的解决方案,回调函数和事件——更合理和更强大,Promise 是一个对象,从它可以获取异步操作的消息,Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject,基本样例:

 
  1. const promise = new Promise((resolve, reject)=>{

  2. ses.sendEmail(params, function(err, data) {

  3. if (err) {

  4. reject (err);

  5. } else {

  6. resolve(data);

  7. }

  8. });

  9. });

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

 
  1. promise.then(function(value) {

  2. resolved(value);

  3. }, function(error) {

  4. rejected(error);

  5. });

但是一般不要在then方法里面定义reject状态的回调函数,强烈建议使用catch的方式进行处理,上面的写法可以改写为下面这种更加合理:

 
  1. promise.then(function(data) {

  2.     resolved(value);

  3. }).catch(function(err) {

  4.     console.log(error)

  5. });

因为改写后的方式,既可以捕获前面then方法执行中的错误,也更接近同步的写法(try/catch

 

async/await

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

async有很多种使用形式:

 
  1. // 函数声明

  2. async function foo() {}

  3.  
  4. // 函数表达式

  5. const foo = async function () {};

  6.  
  7. // 对象的方法

  8. let obj = { async foo() {} };

  9. obj.foo().then(...)

  10.  
  11. // Class 的方法

  12. class Storage {

  13. constructor() {

  14. this.cachePromise = caches.open('avatars');

  15. }

  16.  
  17. async getAvatar(name) {

  18. const cache = await this.cachePromise;

  19. return cache.match(`/avatars/${name}.jpg`);

  20. }

  21. }

  22.  
  23. const storage = new Storage();

  24. storage.getAvatar('jake').then(…);

  25.  
  26. // 箭头函数

  27. const foo = async () => {};

 

我们可以测试一下async的返回值,写一个test.js

 
  1. async function testAsync() {

  2. return "hello async";

  3. }

  4.  
  5. const result = testAsync();

  6. console.log(result);

MacdeMac-mini:work mac$ node test.js

Promise { 'hello async' }

运行之后发现,输出的是一个Promise对象,由此可知async 函数返回的是一个 Promise 对象,实际上async/await就是为了解决Promise写异步时then调用链的问题,如果我们在一个普通的函数里面没法使用await(await必须要在async函数里面才可以使用)来获取async函数的返回值的话,我们就可以用then的方式进行处理

 
  1. testAsync().then(v => {

  2. console.log(v); // 输出 hello async

  3. });

我们可以认为await实际上是在等待async函数执行完成,因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值——这也可以说是 await 在等 async 函数,它等的实际是一个返回值。

 
  1. async function testAsync() {

  2. return "hello async";

  3. }

  4.  
  5. async function test() {

  6. const value = await testAsync();

  7. console.log(value);

  8. }

  9. test();

当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

 

一个函数要调用一个异步方法,同时该函数需要有返回值,我们可以这么写

 
  1. exports.handler = async (event) => {

  2. var params = ""

  3. const result = await test_async(params);

  4. return result;

  5. };

  6.  
  7. function test_async(params){

  8. const promise = new Promise((resolve, reject)=>{

  9. ses.sendEmail(params, function(err, data) {

  10. if (err) {

  11. reject (err);

  12. } else {

  13. resolve(data);

  14. }

  15. });

  16. });  

 
  1. return promise;

  2.  
  3. }

上面的test_async这个方法并没有写async,但是实际上由于test_async这个方法本身返回的就是一个Promise对象,我们知道async所起的作用就是返回一个Promise的(上面提到过),所以这个地方可以不用写async效果一样的。然后我们就可以使用await来获取test_async的返回值,并且作为函数的return返回

 

Promise和Async/Await两种方式比较

假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于之前每个步骤的结果。我们仍然用 setTimeout 来模拟异步操作:

 
  1. function takeLongTime(n) {

  2. return new Promise(resolve => {

  3. setTimeout(() => resolve(n + 200), n);

  4. });

  5. }

  6. function step1(n) {

  7. console.log(`step1 with ${n}`);

  8. return takeLongTime(n);

  9. }

  10.  
  11. function step2(m, n) {

  12. console.log(`step2 with ${m} and ${n}`);

  13. return takeLongTime(m + n);

  14. }

  15.  
  16. function step3(k, m, n) {

  17. console.log(`step3 with ${k}, ${m} and ${n}`);

  18. return takeLongTime(k + m + n);

  19. }


 

把这个需求分别用Promise和async/await进行改造

Promise使用Then来改造:

 
  1. function doIt() {

  2. console.time("doIt");

  3. const time1 = 300;

  4. step1(time1)

  5. .then(time2 => {

  6. return step2(time1, time2)

  7. .then(time3 => [time1, time2, time3]);

  8. })

  9. .then(times => {

  10. const [time1, time2, time3] = times;

  11. return step3(time1, time2, time3);

  12. })

  13. .then(result => {

  14. console.log(`result is ${result}`);

  15. console.timeEnd("doIt");

  16. });

  17. }

  18.  
  19. doIt();

使用async/await进行改造:

 
  1. async function doIt() {

  2. console.time("doIt");

  3. const time1 = 300;

  4. const time2 = await step1(time1);

  5. const time3 = await step2(time1, time2);

  6. const result = await step3(time1, time2, time3);

  7. console.log(`result is ${result}`);

  8. console.timeEnd("doIt");

  9. }

  10.  
  11. doIt();

可以看出来async更加简单

 

async注意事项

1:如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject。所以最好把await命令放到try catch中进行处理

 
  1. async function myFunction() {

  2. try {

  3. await test_async();

  4. } catch (err) {

  5. console.log(err);

  6. }

  7. }

当然也可以这么写:

 
  1. async function myFunction() {

  2. await test_async()

  3. .catch(function (err) {

  4. console.log(err);

  5. });

  6. }

但是建议还是使用第一种方式比较好,更加符合同步的处理方式。

如果有多个await,可以统一的放到try catch处理。

2:多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。

 
  1. let foo = await getFoo();

  2. let bar = await getBar();

上面代码中,getFoogetBar是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有getFoo完成以后,才会执行getBar,完全可以让它们同时触发。

 
  1. // 写法一

  2. let [foo, bar] = await Promise.all([getFoo(), getBar()]);

  3.  

 

3:await命令只能用在async函数之中,如果用在普通函数,就会报错

 

4:如果在调用async函数的时候没有写await,那么他会被立刻执行,因为async返回的是Promise对象,而Promise的特点是无等待,那么也就是说在没有await的情况下执行async函数,该函数会立马执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。

 
  1. router.get('/', function(req, res) {

  2. const html = test_async();

  3. console.log(html);

  4. res.sendWithLog(html);

  5. });

  6.  
  7. async function test_async() {

  8. var value = 'hello async';

  9. return value;

  10. }

 

输入http://127.0.0.1:8080/test,前端得不到我们要的值,控制台打印的是一个Promise对象,因为调用test_async的这个方式是一个非async的方法,所以不能用await,前面提到过如果没法写await,这个时候可以使用then来获取返回值。

我们可以改造一下,在调动test_async的时候加上await再看下效果:

 
  1. router.get('/test', function(req, res) {

  2. get_v(res);

  3. });

  4. async function get_v(res) {

  5. const html = await test_async();

  6. res.sendWithLog(html);

  7. }

  8.  
  9. async function test_async() {

  10. var value = 'hello async';

  11. return value;

  12. }

此时输入http://127.0.0.1:8080/test,前端得到的是hello async,得到了我们想要的值 --------------------- 本文来自 总有刁明想害朕 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/Crystalqy/article/details/80586494?utm_source=copy

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值