中国福彩网双色球号码|中国福彩网刮刮乐

全國咨詢熱線:400-618-4000

目前最好的js異步

創建時間:2019年01月10日15時19分

構建一個應用程序總是會面對異步調用,不論是在 Web 前端界面,還是 Node.js 服務端都是如此,JavaScript 里面處理異步調用一直是非常惡心的一件事情。以前只能通過回調函數,后來漸漸又演化出來很多方案,最后 Promise 以簡單、易用、兼容性好取勝,但是仍然有非常多的問題。其實 JavaScript 一直想在語言層面徹底解決這個問題,在 ES6 中就已經支持原生的 Promise,還引入了 Generator 函數,終于在 ES7 中決定支持 async 和 await。
基本語法
async/await 究竟是怎么解決異步調用的寫法呢?簡單來說,就是將異步操作用同步的寫法來寫。先來看下最基本的語法(ES7 代碼片段):
[JavaScript] 純文本查看 復制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
const f = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(123);
    }, 2000);
  });
};
 
const testAsync = async () => {
  const t = await f();
  console.log(t);
};
 
testAsync();
首先定義了一個函數 f,這個函數返回一個 Promise,并且會延時 2 秒,resolve 并且傳入值 123。testAsync 函數在定義時使用了關鍵字 async,然后函數體中配合使用了 await,最后執行 testAsync。整個程序會在 2 秒后輸出 123,也就是說 testAsync 中常量 t 取得了 f 中 resolve 的值,并且通過 await 阻塞了后面代碼的執行,直到 f 這個異步函數執行完。
對比 Promise
僅僅是一個簡單的調用,就已經能夠看出來 async/await 的強大,寫碼時可以非常優雅地處理異步函數,徹底告別回調惡夢和無數的 then 方法。我們再來看下與 Promise 的對比,同樣的代碼,如果完全使用 Promise 會有什么問題呢?
[JavaScript] 純文本查看 復制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
const f = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(123);
    }, 2000);
  });
};
 
const testAsync = () => {
  f().then((t) => {
    console.log(t);
  });
};
 
testAsync();
從代碼片段中不難看出 Promise 沒有解決好的事情,比如要有很多的 then 方法,整塊代碼會充滿 Promise 的方法,而不是業務邏輯本身,而且每一個 then 方法內部是一個獨立的作用域,要是想共享數據,就要將部分數據暴露在最外層,在 then 內部賦值一次。雖然如此,Promise 對于異步操作的封裝還是非常不錯的,所以 async/await 是基于 Promise 的,await 后面是要接收一個 Promise 實例。

異常處理
通過使用 async/await,我們就可以配合 try/catch 來捕獲異步操作過程中的問題,包括 Promise 中 reject 的數據。
[JavaScript] 純文本查看 復制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
const f = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(234);
    }, 2000);
  });
};
const testAsync = async () => {
  try {
    const t = await f();
    console.log(t);
  } catch (err) {
    console.log(err);
  }
};
testAsync();
代碼片段中將 f 方法中的 resolve 改為 reject,在 testAsync 中,通過 catch 可以捕獲到 reject 的數據,輸出 err 的值為 234。try/catch 使用時也要注意范圍和層級。如果 try 范圍內包含多個 await,那么catch 會返回第一個 reject 的值或錯誤。
[JavaScript] 純文本查看 復制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const f1 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(111);
    }, 2000);
  });
};
const f2 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(222);
    }, 3000);
  });
};
const testAsync = async () => {
  try {
    const t1 = await f1();
    console.log(t1);
    const t2 = await f2();
    console.log(t2);
  } catch (err) {
    console.log(err);
  }
};
testAsync();
如代碼片段所示,testAsync 函數體中 try 有兩個 await 函數,而且都分別 reject,那么 catch 中僅會觸發 f1 的 reject,輸出的 err 值是 111。
開始使用
無論是 Web 前端還是 Node.js 服務端,都可以通過預編譯的手段實現使用 ES6 和 ES7 來寫代碼,目前最流行的方案是通過 [color=var(--link-color)]Babel 將使用 ES7、ES6 寫的代碼編譯為 E6 或 ES5 的代碼來執行。
Node.js 服務端配置
服務端使用 Babel,最簡單的方式是通過 require hook。
首先安裝 Babel:
$ npm install babel-core --save
安裝 async/await 支持:
$ npm install babel-preset-stage-3 --save
在服務端代碼的根目錄中配置 .babelrc 文件,內容為:
{  "presets": ["stage-3"]}
在頂層代碼文件(server.js 或 app.js 等)中引入 Babel 模塊:
require("babel-core/register");
在這句后面引入的模塊,都將會自動通過 babel 編譯,但當前文件不會被 babel 編譯。另外,需要注意 Node.js 的版本,如果是 4.0 以上的版本則默認支持絕大部分 ES6,可以直接啟動。但是如果是 0.12 左右的版本,就需要通過 node -harmony 來啟動才能夠支持。因為 stage-3 模式,Babel 不會編譯基本的 ES6 代碼,環境既然支持又何必要編譯為 ES5?這樣做也是為了提高性能和編譯效率。
配置 Web 前端構建
可以通過增加 Gulp 的預編譯 task 來支持。
首先安裝 gulp-babel 插件:
$ npm install gulp-babel --save-dev
然后編寫配置:

[JavaScript] 純文本查看 復制代碼
1
2
3
4
5
6
7
8
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'));
});
除了 Gulp-babel 插件,也可以使用官方的 Babel-loader 結合 Webpack 或 Browserify 使用。
要注意的是,雖然官方也有純瀏覽器版本的 Babel.js,但是瀏覽器限制非常多,而且對客戶端性能影響也較大,不推薦使用。


作者:傳智播客前端與移動開發培訓學院

首發: http://web.itcast.cn

中国福彩网双色球号码