附件2:async/await

在實際開發中總會遇到許多異步的問題,最多見的場景即是接口請求以後必定要等一段時間才能獲得結果,若是遇到多個接口先後依賴,那麼問題就變得複雜。你們都一直在嘗試使用更好的方案來解決這些問題。最開始只能利用回調函數,後來開始有人使用Promise的思惟來搞定。到ES6中開始支持原生的Promise,引入Generator函數。javascript

直到ES7,有了async/awaitvue

這是一個用同步的思惟來解決異步問題的方案。java

我想不少人可能還不太分得清同步與異步的區別。若是你已經完全瞭解了事件循環,那麼想必對異步的概念應該很是瞭解。當咱們發出了請求,並不會等待響應結果,而是會繼續執行後面的代碼,響應結果的處理在以後的事件循環中解決。那麼同步的意思,就是等結果出來以後,代碼纔會繼續往下執行。react

咱們能夠用一個兩人問答的場景來比喻異步與同步。A向B問了一個問題以後,不等待B的回答,接着問下一個問題,這是異步。A向B問了一個問題以後,而後就笑呵呵的等着B回答,B回答了以後他纔會接着問下一個問題,這是同步。jquery

那麼咱們先記住這個特色,async/await使用同步的思惟,來解決異步的問題。webpack

在繼續分析它的語法與使用以前,咱們先介紹一下如何在咱們的開發環境中支持該語法。程序員

若是你已經知道如何配置,可跳過web

1、如何在本身的開發環境中支持async/await語法

這裏主要介紹兩種方式。vue-cli

1. webpack中支持該語法

首先在當前項目中使用npm下載babel-loadernpm

> npm install babel-loader --save-dev

而後在配置文件webpack.confing.dev.js中配置,在module.exports.module.rules中添加以下配置元素便可。

{
    test: /\.(js|jsx)$/, include: paths.appSrc, loader: require.resolve('babel-loader'), options: { cacheDirectory: true, }, }, 

若是你使用最新版本的create-react-app或者vue-cli來構建你的代碼,那麼它們應該已經支持了該配置。

2. gulp中支持該語法

首先安裝gulp插件

> npm install gulp-babel --save-dev

而後編寫任務

var gulp = require('gulp'); var babel = require('gulp-babel'); gulp.task('babel', function() { return gulp.src('src/app.js') .pipe(babel()) .pipe(gulp.dest('dist')); }); 

2、如何使用

async函數是Generator的一個語法糖。若是你不知道Generator是什麼函數也沒有關係,咱們只須要知道async函數實際上返回的是一個Promise對象便可。

async function fn() { return 30; } // 或者 const fn = async () => { return 30; } 

在聲明函數時,前面加上關鍵字async,這就是async的用法。當咱們用console.log打印出上面聲明的函數fn,咱們能夠看到以下結果:

console.log(fn()); // result Promise = { __proto__: Promise, [[PromiseStatus]]: "resolved", [[PromiseValue]]: 30 } 

很顯然,fn的運行結果其實就是一個Promise對象。所以咱們也可使用then來處理後續邏輯。

fn().then(res => {
    console.log(res); // 30 }) 

await的含義爲等待。意思就是代碼須要等待await後面的函數運行完而且有了返回結果以後,才繼續執行下面的代碼。這正是同步的效果。

可是咱們須要注意的是,await關鍵字只能在async函數中使用。而且await後面的函數運行後必須返回一個Promise對象才能實現同步的效果。

當咱們使用一個變量去接收await的返回值時,該返回值爲Promise中resolve出來的值(也就是PromiseValue)。

 1 // 定義一個返回Promise對象的函數
 2 function fn() {
 3     return new Promise((resolve, reject) => {
 4         setTimeout(() => {
 5             resolve(30);
 6         }, 1000);
 7     })
 8 }
 9 
10 // 而後利用async/await來完成代碼
11 const foo = async () => {
12     const t = await fn();
13     console.log(t);
14     console.log('next code');
15 }
16 
17 foo();
18 
19 // result:
20 // 30
21 // next code

運行這個例子咱們能夠看出,當在async函數中,運行遇到await時,就會等待await後面的函數運行完畢,而不會直接執行next code

若是咱們直接使用then方法的話,想要達到一樣的結果,就不得不把後續的邏輯寫在then方法中。

const foo = () => { return fn().then(t => { console.log(t); console.log('next code'); }) } foo(); 

很顯然若是使用async/await的話,代碼結構會更加簡潔,邏輯也更加清晰。

異常處理

在Promise中,咱們知道是經過catch的方式來捕獲異常。而當咱們使用async時,則經過try/catch來捕獲異常。

 1 function fn() {
 2     return new Promise((resolve, reject) => {
 3         setTimeout(() => {
 4             reject('some error.');
 5         }, 1000);
 6     })
 7 }
 8 
 9 const foo = async () => {
10     try {
11         await fn();
12     } catch (e) {
13         console.log(e);  // some error
14     }
15 }
16 
17 foo();

若是有多個await函數,那麼只會返回第一個捕獲到的異常。

 1 function fn1() {
 2     return new Promise((resolve, reject) => {
 3         setTimeout(() => {
 4             reject('some error fn1.');
 5         }, 1000);
 6     })
 7 }
 8 function fn2() {
 9     return new Promise((resolve, reject) => {
10         setTimeout(() => {
11             reject('some error fn2.');
12         }, 1000);
13     })
14 }
15 
16 const foo = async () => {
17     try {
18         await fn1();
19         await fn2();
20     } catch (e) {
21         console.log(e);  // some error fn1.
22     }
23 }
24 
25 foo();
實踐

在實踐中咱們遇到異步場景最多的就是接口請求,那麼這裏就以jquery中的$.get爲例簡單展現一下如何配合async/await來解決這個場景。

// 先定義接口請求的方法,因爲jquery封裝的幾個請求方法都是返回Promise實例,所以能夠直接使用await函數實現同步
 1 const getUserInfo = () => $.get('xxxx/api/xx');
 2 
 3 const clickHandler = async () => {
 4     try {
 5         const resp = await getUserInfo();
 6         // resp爲接口返回內容,接下來利用它來處理對應的邏輯
 7         console.log(resp);
 8 
 9         // do something
10     } catch (e) {
11         // 處理錯誤邏輯
12     }
13 }

爲了保證邏輯的完整性,在實踐中try/catch必不可少。總之,不處理錯誤邏輯的程序員不是好程序員。

與Promise相比,我的認爲async/await有必定的簡潔性,但也並不是就比Promise有絕對的優點,所以只能算是提供了另一種一樣很棒的方式,至於你們學習以後選擇哪一種方式來解決本身的問題,我認爲這僅僅只是我的的喜愛問題。

相關文章
相關標籤/搜索