异步解决方案async & await 及在Gulp和WebPack中的使用

前言

  • async & await 是目前为止最好的异步解决方案
  • 从回调函数的形式 =》es6提出的promise =》es8提出的async & await
  • async & await将异步处理做到了极致 => 用同步代码的方式来处理异步

举例

下面我们来简单的看一个示例:存在异步请求A和B,当A的返回值为success执行B

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
var A = () => {
return new Promise(function(resolve, reject){
setTimeout(function(){
resolve("success");
},3000);
})
}

var B = () => {
return new Promise(function(resolve, reject){
setTimeout(function(){
resolve("done");
//reject("error");
},1000);
})
}

//Promise + then
A().then(res => {
if (res == "success") {
return B();
}else{
console.log("error");
}
})
.then(res => {
console.log(res);
})
.catch(error => {
console.log(error);
});

//async
(async () => {
try {
const a = await A();
if (a == "success") {
const b = await B();
console.log(b);
}else{
console.log("error");
}
} catch (error) {
console.log(error);
}
})();

从上面的示例可以看到async & await的优势:

  • 处理我们常遇到的条件判别和中间值显得异常清晰
  • 处理逻辑不需要再新建匿名函数,大大减少代码量,结构清晰
  • 错误捕获可以使用try/catch结构轻松捕获

好处说完了,但是因为大佬是es8的新特性,浏览器还没支持。因此下面会介绍怎么在最常用的两种构建工具(gulp和webpack)中配合babel来真正的在我们的生产环境使用它

在构建工具中的使用

webpack篇

需要用到的包

1
2
npm i --save-dev webpack webpack-cli babel-loader babel-core babel-preset-env babel-plugin-transform-runtime
npm i --save babel-runtime

webpack遵循commonJs规范,所以我们完全不需要去单独处理各模块的依赖。
在这个模块化的年代,或许这也是我更钟爱webpack的原因吧

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// webpack.config.js
module.exports = {
entry:{
main: __dirname + "/index.js"
},
output:{
path: __dirname + "/dist",
filename: "index.bundle.js"
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
}
]
}
}

.babelrc

1
2
3
4
5
6
7
//babel 配置
{
"plugins": ["transform-runtime"], //注意plugin 优先级高于presets
"presets": [
["env"]
]
}

Gulp篇

正确姿势

这是gulp + browserify正确使用方式,如若你是gulp新手请参照下面的简单版本
这里先讲述正确使用方法

你需要用到的包:

1
2
npm i --save-dev gulp gulp-uglify gulp-buffer vinyl-source-stream babelify babel-core babel-preset-env babel-plugin-transform-runtime browserify
npm i --save babel-runtime

这里babel-runtime相当于是我们的polyfill,我们使用transform-runtime来动态的去引入需要的部分,避免污染

很多人会疑问为什么会使用到browserify?下面敲重点:

  • 这得从babel谈起,通俗点说,babel可以将浏览器还没支持的es的新写法编译为浏览器支持的语法。
  • 而es中新增的api则不会被转换,这时候我们就得引入polyfill解决。
  • 而babel转换的代码其实是遵循commonJs规范的,浏览器环境显然不支持,因此再用browserify处理各模块间的关系即可。

然后又有人问了gulp-buffer vinyl-source-stream是什么鬼?下面还是重点:
这里我只做基本的介绍,这属于gulp的高级技巧,想刨根问底的童鞋请先了解以下知识

​下面是简单介绍​:

  • 首先,gulp使用了vinyl-fs,而vinyl-fs使用的核心是vinyl,vinyl 可以创建一个文件描述对象,通过接口可以取得该文件所对应的数据(Buffer类型)、cwd路径、文件名等等。
  • 因此按照我们入乡随俗的道理,要想使用gulp是不是得把可读流转换为vinyl file object?那么vinyl-source-stream(可以将普通流转换为vinyl file object stream),vinyl-source-buffer(可以将普通流转换为vinyl file object buffer)它们就来了,按需使用即可。
  • vinyl file object拥有一个属性来表示里面是buffer还是流,gulp默认使用buffer。像一些gulp的插件也是基于buffer的实现(比如gulp-uglify),因此gulp-buffer它来了。反之基于流的插件也可以使用gulp-streamify转换成流再进行处理。

gulpfile.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//gulpfile.js
var gulp = require('gulp'),
babelify = require('babelify'),
notify = require('gulp-notify'), //按需使用
browserify = require('browserify'),
buffer = require('gulp-buffer'), //vinyl-buffer也可
uglify = require('gulp-uglify'),
source = require('vinyl-source-stream'); //vinyl-source-buffer 按需使用

gulp.task('default', function () {
browserify('./index.js')
.transform("babelify", {plugins: ["transform-runtime"],presets: [["env"]]}) //babel处理
.bundle() //处理模块依赖
.pipe(source("index.js")) //转换为vinyl文件对象
.pipe(buffer()) //转换为buffer以便进行代码压缩
.pipe(uglify())
.pipe(gulp.dest('./dist'))
.pipe(notify({
message: 'javascript compile complete'
}));
});

简单版本,不推荐

gulp-browserify已经被官方拉入黑名单,作者也停止维护了。新手入门可以使用

你需要用到的包

1
2
npm i --save-dev gulp gulp-babel babel-core babel-preset-env babel-plugin-transform-runtime gulp-browserify
npm i --save babel-runtime

gulp-browserify来自动处理模块依赖

gulpfile.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//gulpfile.js
var gulp = require('gulp'),
babel = require('gulp-babel'),
notify = require('gulp-notify'),
browserify = require('gulp-browserify');

gulp.task('default', function () {
gulp.src('./index.js')
.pipe(babel())
.pipe(browserify())
.pipe(gulp.dest('./dist'))
.pipe(notify({
message: 'javascript compile complete'
}));
});
1
// babel 配置同webpack篇

参考文章:
6-reasons-why-javascripts-async-await-blows-promises

Do the best!