千家信息网

JS中使用async await的方法教程

发表于:2024-11-11 作者:千家信息网编辑
千家信息网最后更新 2024年11月11日,本篇内容介绍了"JS中使用async await的方法教程"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所
千家信息网最后更新 2024年11月11日JS中使用async await的方法教程

本篇内容介绍了"JS中使用async await的方法教程"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

目录
  • jQuery的$.ajax

  • Webpack时代的开始

  • 深入了解Promise

  • 消灭嵌套

  • await-to-js

  • 总结

jQuery的$.ajax

在开始之前我们先来聊聊我的js异步之路。在我还在学校的时候,那时候还是 jQuery 的天下,我直接接触到并且经常使用的异步操作就是网络请求,一手 $.ajax 走天下,伴我过了大二到毕业后差不多大半年的时间。

$.ajax( "/xxx" )  .done(function() {    // success !!! do something...  })  .fail(function() {    // fail !!! do something...  })  .always(function() {    // loading finished..  });

不可否认,$.ajax 这个东西还是挺好使的,在面对大部分场景只有一个请求的情况下,完全胜任甚至觉得很棒

但是有个大大的问题,那就是面对请求链的时候就会特别特别的糟心,比如一个请求依赖于另一个请求的结果,两个可能还无所谓,要是五个八个的,可能想要直接自杀。。。

$.ajax('/xxx1')  .done(function() {    // success !!! do something...    $.ajax('/xxx2')      .done(function() {        // success !!! do something...        $.ajax('/xxx3')          .done(function() {            // success !!! do something...            $.ajax('/xxx4')              .done(function() {                // success !!! do something...                $.ajax('/xxx5')                  .done(function() {                    // success !!! do something...                    // more...                  })                  .fail(function() {                    // fail !!! do something...                  })                  .always(function() {                    // loading finished..                  });              })              .fail(function() {                // fail !!! do something...              })              .always(function() {                // loading finished..              });          })          .fail(function() {            // fail !!! do something...            $.ajax('/xxx6')              .done(function() {                // success !!! do something...                $.ajax('/xxx7')                  .done(function() {                    // success !!! do something...                    // more....                  })                  .fail(function() {                    // fail !!! do something...                  })                  .always(function() {                    // loading finished..                  });              })              .fail(function() {                // fail !!! do something...              })              .always(function() {                // loading finished..              });          })          .always(function() {            // loading finished..          });      })      .fail(function() {        // fail !!! do something...      })      .always(function() {        // loading finished..      });  })  .fail(function() {    // fail !!! do something...  })  .always(function() {    // loading finished..  });

抱歉,我不知道你可以套这么多层。。。,但事实就是TM经常出现这样的流程,大伙儿说说,这不能怪产品吧???只能怪自己学艺不精

像这样链式操作,我觉得吧,是个人可能都是奔溃的,先不说代码的可读性,就拿天天在变化的产品需求来说,也许先前是 请求1 结束之后紧接着 请求2 、 请求3 ,后面产品大手一挥,我觉得这个流程不大对,后面就变成了 请求2、 请求3 、 请求1,这尼玛套娃怎么改?可能有人会有疑问,为啥不用 axios 、 await 、async 呢?这个就不得不提项目代码是08年开写的JSP了。。。。在整了大半年的屎上拉屎以后,迎来了大大的转机,新写的项目开始往 Vue 上面转,并且放弃一部分兼容性,我TM直接起飞。。。

Webpack时代的开始

新的项目直接Vue + Webpack,我直接就给安排上 axios 、 await 、async ,现在代码非常好使,嵌套N层的代码没了

const r1 = await doSomthing1();if (r1.xxx === 1) {  const r2 = await doSomthing2(r1);  const r3 = await doSomthing3(r2);  // do something....} else {  const r4 = await doSomthing4(r1);  const r5 = await doSomthing5(r4);  // do something....}// do something....

但是上面的代码存在一个问题,如果某个任务报错,那么代码直接就终止了。。。这样不符合我们的预期啊,那我们加上 try catch

let r1;try {  r1 = await doSomthing1();} catch (e) {  // do something...  return;}if (r1) {  if (r1.xxx === 1) {    let r2;    try {      r2 = await doSomthing2(r1);    } catch (e) {      // do something...      return;    }    if (r2) {      let r3;      try {        r3 = await doSomthing3(r2);      } catch (e) {        // do something...        return;      }      // do something...    }  } else {    let r4;    try {      r4 = await doSomthing4(r1);    } catch (e) {      // do something...      return;    }    if (r4) {      let r5;      try {        r5 = await doSomthing5(r4);      } catch (e) {        // do something...        return;      }    }    // do something...  }  // do something...}

???

优化了,等于没优化。。。

这时候我想聪明的小伙伴可能会说了,这是啥煎饼玩意儿。而呆滞的小伙伴已经开始想怎么解决这样的问题了。。。

深入了解Promise

我们来看一下 Promise 的定义

/** * Represents the completion of an asynchronous operation */interface Promise {    /**     * Attaches callbacks for the resolution and/or rejection of the Promise.     * @param onfulfilled The callback to execute when the Promise is resolved.     * @param onrejected The callback to execute when the Promise is rejected.     * @returns A Promise for the completion of which ever callback is executed.     */    then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise;    /**     * Attaches a callback for only the rejection of the Promise.     * @param onrejected The callback to execute when the Promise is rejected.     * @returns A Promise for the completion of the callback.     */    catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise;}

then 和 catch 都会返回一个新的 Promise ,我相信很多小伙伴都已经想到了怎么解决方法,需要使用 try catch 是因为它会报错,那我们返回一个 永远不会报错的结果 不就行了?说干就干

消灭嵌套

function any(promise) {  return promise.then((v) => v).catch((_) => null);}

这样就完全解决了啊???通过判断是否有值来判断是否成功,就不用再写 try catch 了,但是这样的代码有点不大好使,如果 then 返回的是一个 void 那么就完犊子了,一个 undefined 一个 null ,这还判断个锤子,我们再来改进一下

function any(promise) {  return promise    .then((v) => ({ ok: v, hasErr: false }))    .catch((e) => ({ err: e, hasErr: true }));}

使用的话

const r = await any(doSomething());if (r.hasErr) {  console.log(r.err);  return;}console.log(r.ok);

现在看起来是不是很完美呢,赶紧和小伙伴推销一下。

小伙伴:???这啥煎饼玩意儿,不用不用。

我:这个我写的,在异步中用起来很好使的,告别嵌套 try catch ,巴拉巴拉。。。

小伙伴:好的,下次一定用。

大家肯定有遇到过这样的情况,大家写的代码互相看不起,只要不是三方库,大家都是能不用同事写的就不用。。。

await-to-js

我都以为只有我一人欣赏,这一份优雅。事情出现转机,某天我正在刷github,发现了一个和我差不多异曲同工之妙的东西 await-to-js ,几行代码透露了和我一样的执着

// 下面是最新的代码/** * @param { Promise } promise * @param { Object= } errorExt - Additional Information you can pass to the err object * @return { Promise } */export function to (  promise: Promise,  errorExt?: object): Promise<[U, undefined] | [null, T]> {  return promise    .then<[null, T]>((data: T) => [null, data])    .catch<[U, undefined]>((err: U) => {      if (errorExt) {        Object.assign(err, errorExt);      }      return [err, undefined];    });}export default to;

再贴上使用示例

import to from 'await-to-js';// If you use CommonJS (i.e NodeJS environment), it should be:// const to = require('await-to-js').default;async function asyncTaskWithCb(cb) {     let err, user, savedTask, notification;     [ err, user ] = await to(UserModel.findById(1));     if(!user) return cb('No user found');     [ err, savedTask ] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));     if(err) return cb('Error occurred while saving task');    if(user.notificationsEnabled) {       [ err ] = await to(NotificationService.sendNotification(user.id, 'Task Created'));       if(err) return cb('Error while sending notification');    }    if(savedTask.assignedUser.id !== user.id) {       [ err, notification ] = await to(NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you'));       if(err) return cb('Error while sending notification');    }    cb(null, savedTask);}async function asyncFunctionWithThrow() {  const [err, user] = await to(UserModel.findById(1));  if (!user) throw new Error('User not found');  }

"JS中使用async await的方法教程"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0