溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JS中使用async await的方法教程

發(fā)布時間:2021-10-08 09:32:26 來源:億速云 閱讀:125 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“JS中使用async await的方法教程”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

目錄
  • jQuery的$.ajax

  • Webpack時代的開始

  • 深入了解Promise

  • 消滅嵌套

  • await-to-js

  • 總結(jié)

jQuery的$.ajax

在開始之前我們先來聊聊我的js異步之路。在我還在學校的時候,那時候還是 jQuery 的天下,我直接接觸到并且經(jīng)常使用的異步操作就是網(wǎng)絡請求,一手 $.ajax 走天下,伴我過了大二到畢業(yè)后差不多大半年的時間。

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

不可否認,$.ajax 這個東西還是挺好使的,在面對大部分場景只有一個請求的情況下,完全勝任甚至覺得很棒

但是有個大大的問題,那就是面對請求鏈的時候就會特別特別的糟心,比如一個請求依賴于另一個請求的結(jié)果,兩個可能還無所謂,要是五個八個的,可能想要直接自殺。。。

$.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經(jīng)常出現(xiàn)這樣的流程,大伙兒說說,這不能怪產(chǎn)品吧???只能怪自己學藝不精

像這樣鏈式操作,我覺得吧,是個人可能都是奔潰的,先不說代碼的可讀性,就拿天天在變化的產(chǎn)品需求來說,也許先前是 請求1 結(jié)束之后緊接著 請求2 、 請求3 ,后面產(chǎn)品大手一揮,我覺得這個流程不大對,后面就變成了 請求2、 請求3 、 請求1,這尼瑪套娃怎么改?可能有人會有疑問,為啥不用 axios 、 await 、async 呢?這個就不得不提項目代碼是08年開寫的JSP了。。。。在整了大半年的屎上拉屎以后,迎來了大大的轉(zhuǎn)機,新寫的項目開始往 Vue 上面轉(zhuǎn),并且放棄一部分兼容性,我TM直接起飛。。。

Webpack時代的開始

新的項目直接Vue + Webpack,我直接就給安排上 axios 、 await 、async ,現(xiàn)在代碼非常好使,嵌套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...
}

???

優(yōu)化了,等于沒優(yōu)化。。。

這時候我想聰明的小伙伴可能會說了,這是啥煎餅玩意兒。而呆滯的小伙伴已經(jīng)開始想怎么解決這樣的問題了。。。

深入了解Promise

我們來看一下 Promise 的定義

/**
 * Represents the completion of an asynchronous operation
 */
interface Promise<T> {
    /**
     * 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<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

    /**
     * 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<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}

then 和 catch 都會返回一個新的 Promise ,我相信很多小伙伴都已經(jīng)想到了怎么解決方法,需要使用 try catch 是因為它會報錯,那我們返回一個 永遠不會報錯的結(jié)果 不就行了?說干就干

消滅嵌套

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);

現(xiàn)在看起來是不是很完美呢,趕緊和小伙伴推銷一下。

小伙伴:???這啥煎餅玩意兒,不用不用。

我:這個我寫的,在異步中用起來很好使的,告別嵌套  try catch ,巴拉巴拉。。。

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

大家肯定有遇到過這樣的情況,大家寫的代碼互相看不起,只要不是三方庫,大家都是能不用同事寫的就不用。。。

await-to-js

我都以為只有我一人欣賞,這一份優(yōu)雅。事情出現(xiàn)轉(zhuǎn)機,某天我正在刷github,發(fā)現(xiàn)了一個和我差不多異曲同工之妙的東西 await-to-js ,幾行代碼透露了和我一樣的執(zhí)著

// 下面是最新的代碼
/**
 * @param { Promise } promise
 * @param { Object= } errorExt - Additional Information you can pass to the err object
 * @return { Promise }
 */
export function to<T, U = Error> (
  promise: Promise<T>,
  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的方法教程”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI