Gulp 实战和原理解析
Posted 前端学习每一天
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gulp 实战和原理解析相关的知识,希望对你有一定的参考价值。
以下文章来源于StuQ ,作者桑世龙
Gulp 实战和原理解析
内容简介:介绍 Gulp 和 Grunt 区别,为什么使用 Gulp,以及我们在项目实战里如何应用 Gulp,最后讲一下 Gulp 的核心原理 Stream,以及基于 Stream 的一些最佳实践。
大家好,我是桑世龙,github 和 cnodejs 上的 i5ting,目前在天津创业,公司目前使用技术主要是 nodejs,算所谓的 MEAN(mongodb + express + angular + node),所有代码都部署在阿里云上。
我的名字 i5ting,原因是我媳妇叫张婷,哈哈~
闲言少叙,下面开始正题 。
本次主要讲 3 部分:
什么是 Gulp,核心概念、用法;
以微信前端组的 weui 为例子,讲解gulp在真实项目里如何使用(包括浏览器实时刷新,watch,less 编译,压缩,生成 sourcemap、release 等);
最后讲解一下 stream 原理,给出更多实践。
1. 什么是 Gulp?
简单的讲,Gulp 是一个构建工具,一个 streaming 构建工具,一个 nodejs 写的构建工具
总之,它是一个构建工具
那么什么是构建工具呢?
构建工具本质就是为了自动化构建,解放程序员、提供程序员效率的工具
我们来举个例子,最早的 make,因为每次都 cc 编译,太恶心了,而且当文件特别多的时候,编译速度又慢下来,能不能按需编译,增量编译?
make 是通过 makefile 文件来描述源程序之间的相互关系并自动维护编译工作的。
例子就不举了,写过 c 的人多少都知道点。
其实编译在每个语言世界里,都是痛,骨子里的风湿一样,于是产生了 make 类似的东西:
比如 java 里的 ant,c# 里的 NAn;
比如 ruby 里 rake;
比如 coffeescript 里有 cake。
它们的共同特点:
基于 task,定义简单;
task 有串行,并行,作业依赖等控制方式;
通过 xxxfile 来定义 task。
如此看来,nodejs 的构建系统也应该是这样的,可以说gulp是node世界里和上面几个构建工具最像的一个,它们太像了,以至于学习起来特别简单。
其实上面还提了一个 streaming,是流式的意思,后面讲原理的时候会深入讲解。
2. 入门指南
2.1. 安装 Gulp
建议全局安装:
$ npm install —global gulp
但最多的是作为项目的开发依赖(devDependencies)安装:
$ npm install —save-dev gulp
2.2. 创建gulpfile
在项目根目录下创建一个名为 gulpfile.js
的文件:
gulpfile 和 makefile、build.xml 等是类似的,定义 task 的地方。
定义好 task,下面运行一下。
2.3. 运行 Gulp
$ gulp
默认的名为 default 的任务(task)将会被运行,在这里,这个任务并未做任何事情。
想要单独执行特定的任务(task),请输入:
gulp <task> <othertask>
是不是很简单?
3. Gulp vs Grunt
下面比较一下 Grunt 和 Gulp:
Gulp 和 Grunt 类似。但相比于 Grunt 的频繁的 IO 操作,Gulp 的流操作,能更快地完成构建。
Grunt 是基 于dsl 声明式写法,出来的早,但写起来比较恶心,可读性非常差。
nodejs 里 sails 的因为基于 Grunt 被鄙视,ionic 里也是,好在 ionic 现在也是 Gulp 的。
鄙视完 Grunt,就该吹吹 Gulp 了。
话说 2014 年 Gulp 火了之后,很快风头就盖过了 Grunt,好不好,试了才知道。
4. why Gulp?
前端本身就对 js 非常了解,Gulp 可以说是 plain js,语法都再简单不过,所以大家比较容易接受。
4.1. 基于nodejs
基于 nodejs 的小而美哲学,写 gulp task 是件很愉快的事儿。
而且还可以结合 nodejs 世界里最好的包管理器 npm,写 cli 或者模块特别简单。
而且可以写 c/c++ addon,给你无限可能。
而且还有 shelljs 这样的库,结合 shell,给你无限可能。
4.2. 易于使用
通过代码优于配置的策略,Gulp 让简单的任务简单,复杂的任务可管理。
而且对 ant,rake,make 等了解的人非常容易上手。
4.3. 构建快速
利用 Node.js stream 的威力,你可以快速构建项目并减少频繁的 IO 操作。
而且 Gulp 的核心代码可以高效利用你所有核的 cpu,高效运行,尤其是大文件处理,后面会讲到。
4.4. 插件机制
Gulp 严格的插件指南确保插件如你期望的那样简洁高质得工作。
4.5. 易于学习
通过最少的 API,掌握 Gulp 毫不费力。
这得益于 Gulp 的设计,api 简单,调用关系和依赖清晰,当然如果理解 linux 管道或者其他类似的构建工具会更容易。
而且每个任务都拆分成一个 task,结构清晰,利用 stream 和 pipe 写法,组成 task,也是非常容易学习的。
4.6. 总结
这里说了 Gulp 的各种好处,它通用,高效,使用简单,学习成本低,总之,我就是要告诉你:
它是非常好的构建工具,而且是长久看好的。
它也有缺点,这样说也不太合适,更准确的说,它是一个通用构建工具,所以在构建实践上,需要写的人有好的实践。
像 fib3 这样的,只是基于比较好的构建实践而已,其他方面是不能和 Gulp 相提并论的。
5. Gulp快速入门
5.1. hello world
都说得来个 hello world。
创建 gulpfile.js:
然后需执行命令:
gulp
定义作业就是这么简单:
default 是名字
后面的匿名函数是它的实现
5.2 自定义作业
将作业名称自定义为 stuq:
然后运行:
gulp stuq
这里的 stuq 是作业名称。
5.3. 依赖作业
这里的 task 有 3 个参数。
default 是方法名称,只有 default 比较奇怪,会默认调用。
相当于 c 里的 main 方法。
[‘watch’] 这是依赖的作业列表,它们是由顺序的,按数组顺序依次执行。
第三个参数是成功执行完上面的依赖作业后执行的回调函数。
这里要强调,依赖作业数组里的都执行完了,才会执行第三个参数,即当前作业具体内容。
我们不妨改一下,看看多个依赖如何定义:
是不是很简单?放心,这只是入门,下面看一下流式处理。
5.4. 流式处理
比如混淆压缩 js,使用 gulp-uglify 插件:
src 是输入
dest 是输出
pipe 是管道的意思,也是 stream 里核心概念,也就是说:上一个的输出,是下一个的输入。
src 里所有 js,经过处理 1,处理 2,然后压缩变成 min.js,中间的处理 pipe 可以 1 步,也可以是 n 步。
反正第一步处理的结果是第二步的输入,以此类推,就像生产线一样,每一步都是一个 task 是不是很好理解呢?
每个独立操作单元都是一个 task,使用 pipe 来组装 tasks。
于是 Gulp 就变成了基于 task 的积木式的工具。
5.5. 总结
好吧,是时候总结一下了:
每一个作业都是独立,定义为 task;
通过 stream 的机制,上一个的输出,作为下一个的输入;
通过 pipe 方法组装 task,完成我们想要的业务逻辑。
至此,task 相关的概念都讲完了,你已经会使用 Gulp 了,找几个插件就足以工作了。
如果想高级玩法,可以自己写插件,可以尝试 Gulp 4 的一些 API,比如并行等。。。
下面看以项目实战。
6. 项目实践
以目前最火的微信前端组的 WeUI 项目为例,看看gulp是如何被使用的(其实是如何使用 Gulp 构建前端项目)。
先说一下 WeUI 是一个什么项目:
WeUI 为微信 Web 服务量身设计的h5框架。
WeUI 是一套同微信原生视觉体验一致的基础样式库,为微信 Web 开发量身设计,可以令用户的使用感知更加统一。包含 button、cell、dialog、toast、article、icon 等各式元素。
它是使用 less 编写,最终编译成 css,压缩成 weui.min.css 的,当然这里面还使用了一下比较好的开发实践:
web server
livereload
watch 实时监控
less:css 预处理器
minify 压缩
sourcemap 生成
等等~~
下面我们来扒光它。
6.1. 准备工作
首先看目录结构。
就几个目录:
有 package.json,说明它是一个 node 模块或者说它依赖了 node 模块
有 gulpfile.js,说明它是使用 Gulp 作为构建工具的。
还有 src 和 dist 目录,一般 src 是源码,dist 是构建后生成的目录,至此,我们似乎明白了点什么。
首先 clone 代码:
git clone https://github.com/weui/weui.git
上面说了,有 package.json,此时需要安装依赖模块:
npm install
至此就准备玩了,下面看一下 gulpfile.js。
6.2. 看一下它有哪些 tasks
看一下它有哪些 tasks,查看命令是: gulp -T
看这个的目的,其实就为了了解当前 gulpfile 里 tasks,以便让大家有一个概况了解。
大概有 7 个 task,其中 styles 和 release 是有依赖作业的。
也就是说,整个项目目前的 task 比较少,比较适合讲解,而且是腾讯公司的项目,大家应该会比较认可一些。
ok,下面我们分别看一下每个 task。
上面讲过,所有的 task 定义在 gulpfile.js 里,那么我们就结合源码,看一下 gulpfile.js 的 task 是如何定义,以及如何应用的。
6.3. default
这是默认作业,也就是在根目录,执行:
gulp
相当于:
gulp default
其实 make,rake,ant 等都有类似约定。
这里面值得说明的是:
这是最简单的 task 定义,无任何依赖作业;
作业里面使用 nodejs 写的 yargs 模块,用户处理 cli 参数。
比如此时可以执行 gulp -s
后者 gulp default -s
然后它就会打开网页,跳转到 http://localhost:8080/example/
从task定义里可知:
if (yargs.s) {
gulp.start(‘server’);
}
说明 server 是一个 task,这里的 start 就相当于 call 或者 invoke 某个 task 的方法。
注:yargs 是一个 nodejs 模块,目前最好的解析 cli 参数的库。
当然,如果这样,是不是太简单了呢?而且亲,你还有 2 个参数没说呢。
是的
-w: 实时监听;
-p: 服务器启动端口,默认8080。
这里要说的就是一个开发惯例,
-p
很好理解,就是 httpserver 的端口 port,如果指定是 7070 那就是 7070,如果没指定就是 8080。
给程序员自己定制的空间,谁还没有个端口自定义权利呢?
-w
比较特殊,这里的 w 是 watch 的意思,就是监控某个文件或目录,只要有变化就触发 xx 动作,一般用于编译,比如 coffee,typescript,less,sass 等。
看一下定义:
if (yargs.w) {
gulp.start(‘release’);
gulp.start(‘watch’);
}
这里的意思的如果有 w 参数,就先调 release task,然后 watch 作业。
这里牵连出 3 个 task,有 server,watch,release,容我慢慢道来。
btw:这里的 if (yargs.w) {
怎么看逻辑都怪怪的,既然有 无w 都执行 release task,这样写法还是有待商榷的。
6.4. server
server task 一看就知道是启动服务器,一般前端开发,都是起一个服务器在浏览器里测试。
所以还是比较容易理解。
看代码:
代码里的几个关键词:
browserSync
server
port
startPath
weinre
browserSync 是一个 nodejs 模块,专门做的是 livereload 的事儿,也就是说,我们在编辑器里写代码,保存了,文件就会变动,文件变动了就会触发操作系统的监控事件,这时让浏览器刷新。
于是,代码变了,不用刷新浏览器就能看到效果。。。
这其实就是传说中得 livereload…
又可以偷懒了,祭奠 f5 吧!!!
其他(server,port,startPath)是 browserSync 的配置项,有兴趣自己扒文件吧。
这里稍稍提一下 weinre,因为 WeUI 这个项目是移动端 html5 页面,所以才会用到 weinre 调试的,是远程调试 HTML5 的利器
总结一下。
整个 server 就是 browserSync 提供的 3 个功能:
起了一个 server
支持 livereload
自动打开网页
还不错吧,下面看一下更实用的一个 task: watch 监控
6.5. watch
watch 其实就干了 2 件事儿:
如果 ‘src/*/.less’ 变动,执行 styles task;
如果 ‘src/example/*/.{html,js}’ 变动,先执行 ‘source’ task,然后livereload通知浏览器。
大家伙只要了解文件变动能干坏事即可,其他可自由发挥。
如果 Gulp 内置的 watch 无法满足,你还可以使用 gulp-watch 这个单独模块,哈哈,如果有兴趣还可以研究一下操作系统底层监控文件变动接口,有点意思。
6.6. release
release 是发布最终 css 的 task:
gulp.task(‘release’, [‘styles’]);
release 只是依赖 styles task,相当于 styles 的别名。
值得说明的是,WeUI 是 less 写的,需要编译成 css,然后最终发布的是 css 文件。
那么,
如果 js 是用 coffeescript,typescript 写的呢?
如果 css 是用 less,sass,stylus 写的呢?
其实都是一样的思路,编译成 js 或 css,然后发布
这些预处理器,让开发方便,高效的同时,也增加了前端的复杂度,真是老子那句话:
福兮祸所伏,祸兮福所倚…
阿门。。。阿弥托佛。。。
下面一个 source task。
6.7. source
上面的都比较简单,只是作业定义和作业依赖定义而已,下面看一下真实的流式处理:
回故一下,上面讲的流式内容:
src是输入
dest是输出
pipe是管道的意思,也是stream里核心概念,也就是说上一个的输出,是下一个的输入。
这代码里的 src 里的,所有不是 less 的文件,都丢到 dist 目录:
简单吧?
然后,它又 pipe 一个,仅仅是为了表示顺序,无上下文件传递关系(偷懒做法而已,不可取)。
这样写起来是不是非常简单?
我知道你会回答是,下面我们来讲个不简单的。
6.8. styles
下面是关于样式处理的 task:
这是整个 gulpfile 里最长的一个 task。
下面拆成 2 部分分析一下:
依赖 source,执行完 source,然后编译 less
编译的 less 有例子和具体要发布的 weui.css
part1
less() 来编译less文件,src 和 dest 大家要看清楚
最后 pipe 了一个 livereload 触发
和上面的 source task 类似,只有 less 编译不一样,这里就不详细讲解了。
下面看一下 part2
src是src/style/weui.less
sourcemaps.init()是初始化sourcemap
less编译
.pipe(sourcemaps.write())是写入sourcemap
.pipe(autoprefixer())自动增加前缀
.pipe(gulp.dest(dist)) 输出到dist目录
.pipe(minify()) 是压缩
.pipe(rename(function (path) 重命名,因为文件后面要加min
.pipe(gulp.dest(dist)) 压缩后的文件进行保存
.pipe(browserSync.reload({stream: true}));是livereload触发
整体是分了 3 个阶段:
编译 less 和生成 sourcemap
压缩 minify
触发 livereload
6.9. 实战总结
至此,我们就讲完了所有 gulpfile 里的内容,以及每个 task 的细节。
结论是:这是一个比较典型的 Gulp 项目,还不错。
当然它也不是非常完美,比如作业依赖可以优化、代码校验检测、release 没有 reversion 处理等。
6.10. package.json
下面简单看一下 package.json。
这里有 2 个地方需要注意:
是 gulpfile 里引用的模块:
“scripts”: {
“test”: “gulp release”
},
执行 npm test 即可发布最终 css。
有人说 Gulp 只是一些命令,没啥技术含量,大家先笑笑,一会我们就来讲讲。
下面看一下 Gulp 的核心原理:nodejs stream
7. 核心:stream
官方文档解释
A stream is an abstract interface implemented by various objects in Node.js. For example a request to an HTTP server is a stream, as is stdout. Streams are readable, writable, or both. All streams are instances of EventEmitter
Stream 是 nodejs 各种对象实现的抽象接口。比如一个 http server 的请求是一个 stream,stdout 也是一个。Streams 可读、可写,或者兼有的。所有的 stream 对象都是 EventEmitter 的实例。
好理解么?
不好理解,还是从流式理解吧~
7.1. 什么是流式
上一个的输出,是下一个的输入
上一个的输出,是下一个的输入
上一个的输出,是下一个的输入
7.2. linux pipe
流式和 linux pipe 是一样的(也可能是最早的起源)。
举例:
ps -ef|grep boot|awk ‘{print $2}’|xargs kill -9
ps -ef 查看进程
grep boot 是过率进程里的和boot相关的所有进程
awk ‘{print $2}’ 取出进程号
xargs kill -9 杀掉该进程
可以看出,上一个的输出,是下一个的输入
7.3. nodejs 里的 stream
下面理解一下 nodejs 里的 stream
等于
知道 Gulp 里的 pipe 是怎么来的了吧?
Stream 在 nodejs 中是 EventEmitter 的实现,并且有多种实现形式,例如:
http responses request
fs read write streams
zlib streams
tcp sockets
child process stdout and stderr
连著名 request 模块都支持 stream
为什么使用 Stream 呢?
node 中的 I/O 是异步的
pipe
基于 buffer 节省内存,适合处理大文件
有事件监控
7.4. 推荐阅读
nodejs 里有五种基本的 Stream:readable,writable,transform,duplex,and “classic”
时间原因,具体使用请自己查阅 API 文档: https://github.com/substack/stream-handbook
7.5. 八卦更多
ruby 作者,松本行弘,上半年基本没干啥,写了一个叫 streem 的语言,
In Streem, a simple cat program looks like this:
stdin | stdout
可见 stream 的上一个输出是下一个输入的应用有多么的深入人心
7.6. orchestrator
下面介绍 Gulp 的核心:
orchestrator 这是 gulp 底层依赖的 task 相关的核心库,它定义了 task 执行方式和依赖,而且支持最大可能的并发。
Gulp 的高效即来源于此。
本身 stream 对大文件读写就非常棒,再加上上面说的种种特性,使得 Gulp 流行是必然的。
8. 更多实践
Gulp 有非常多插件,它可以做的更多。
8.1. i5ting_toc
你好奇该文: http://i5ting.github.io/stuq-gulp/#107 是如何生成 toc 和发布到 git pages 上的么?
这竟然也和 gulp 有关系?
是的,该问是使用 markdown 写的,然后使用 Gulp 把 markdown 生成 html,并 push 到 git pages 上去
实现思路
jquery 写好 toc 插件,https://github.com/i5ting/i5ting_ztree_toc
写生成器,把 markdown 按照 toc 模板生成 html,https://github.com/i5ting/tocmd.npm
写 Gulp 来构建,使用 gulp-gh-pages 和 shelljs 来自动生成
更多参见
如何使用 Gulp 来把 markdown 生成 html 文档并上传到 git pages 上
https://cnodejs.org/topic/5464c7fe88b869cc33a97985
8.2. shipit
Shipit nodejs 写的自动化部署工具,是基于 Gulp 的,很不错。
群里 fundon 大神的项目都是使用shipit部署的。
https://github.com/shipitjs/shipit
8.3 slush
我比较讨厌 Yeoman(YO),好在有一个替代品 slush。
官方介绍:
The streaming scaffolding system - Gulp as a replacement for Yeoman
https://github.com/slushjs/slush
还是不错的,可惜没有红起来,可能时日尚短吧。
9. 全文总结
Gulp 是一个构建工具,一个 streaming 构建工具,一个 nodejs 写的构建工具。
每个操作都是是独立作业task
作业依赖定义非常简单,决定执行顺序
通过pipe组装tasks,完成业务逻辑处理
Gulp 的核心 stream。
先理解什么是流式(重要的事情,大声喊三遍):
上一个的输出,是下一个的输入
上一个的输出,是下一个的输入
上一个的输出,是下一个的输入
好了,你已经是 Gulp 高手了。
最后让我们来展望一下美好的未来:
Gulp是前端世界的主流构建工具,是大多数开源项目的选择,你值得拥有
另外公布一下weui未来会有 reactjs 版本,还是值得期待的。
谢谢大家,今天讲的内容就到这里,如果有什么讲的不对的、不合理的,请不吝赐教,共同学习。
提问环节
1. 请问将 gulp 部署到生产环境上,开启 watch 去时时监听每周升级一次,通过 rsync 过去的文件去自动检测执行。还是每个开发人员都装gulp执行后上传处理过的文件,如果都不是怎么处理?
“开启 watch 去时时监听”,为啥不用 later 这样模块去定时处理呢?
另外每个开发都可以随便更新,显然是不靠谱的。
2. 请问 gulp 的任务都是同步顺序执行的嘛?流式是不是就代表无法异步?为什么老师还提到可以异步呢?
这个讲的原因是 nodejs 里的每个函数都是异步,所以 pipe 的好处相当于顺序执行了。
gulp 里的 pipe 链上的 task 都是同步顺序执行的。但 pipe 链外的不好说
3. 一个 gulp 项目有很多的插件所以 nodemodule 就有很多…然后ide打开跟占用资源 项目都用的是统一的 gulp 插件 如何在不同的项目中调用本地的 不需要每个项目下面都安装
区分产品模式和开发模式,开发模式依赖的占资源是没办法的
如何在不懂项目调试本地的,可以采用软连接的方式,sails 里就是这样用的,所有模块都是 sails 的 nodemodules 里,然后连接到当前项目里
4. src 里所有 js,经过处理 1,处理 2,然后压缩变成 min.js,中间的处理 pipe 可以 1 步,也可以是 n 步 请问关于上面的“然后压缩变成 min.js”,必须是 min,js 么?
这里使用了 rename 插件,可以随意改的,哈哈~
5. gulp.task(‘release’, [‘styles’]); release 只是依赖 styles task,相当于 styles 的别名。请问为什么要起 style 这样的一个别名?好奇怪呀。
语义更明确而已,无他。
6. web ui 层选型,weui、ionic、react ,怎么做选型比较呢?
看做什么,微信开发肯定 weui,打包 app 可以考虑 ionic 这种 hybrid 方式。
react 只是 view 层的解决方案,和移动、pc 无关,所以 weui 才计划出 reactjs 版本。
7. gulp 是如何利用多核的?
orchestrator 这是 gulp 底层依赖的task相关的核心库,它定义了 task 执行方式和依赖,而且支持最大可能的并发
见 https://github.com/orchestrator/orchestrator
8. 根据老师讲的流式,上一个输出是下一个的输入,那么流式是不是可以理解为就像 jquery 的链式操作一样?
类似,相当于 pipe 调用一次都返回当前对象,这样理解也可以,但输出输入这个就不太好理解
链式操作都是在当前对象上下文的
9. D:\app\weui>gulp -s module.js:338 throw err; ^ Error: Cannot find module ‘lodash’ at Function.Module._resolveFilename (module.js:336:15) at Function.Module._load (module.js:286:25) at Module.require (module.js:365:17) at require (module.js:384:17) at Object.
(D:\app\weui\node_modules\browser-sync\lib\hooks.js:3:20) at Module._compile (module.js:434:26) at Object.Module._extensions..js (module.js:452:10) at Module.load (module.js:355:32) at Function.Module._load (module.js:310:12) at Module.require (module.js:365:17) at require (module.js:384:17)
缺少依赖模块,安装上就好了。
另外不建议用 windows 开 发nodejs,问题不好说,我也不太熟悉。
10. 我比较讨厌 Yeoman(YO),好在有一个替代品 slush 请问 为什么“讨厌 Yeoman(YO)”?
个人习惯而已,一般我都自己写生成器,又不能,一个生成器搞的那么复杂,至于么?
11. 请问如何调试 gulp 任务
和 nodejs 调试一样
node debug
node-inspector
tdd/bdd
node-debug 三法三例之 node debugger + node inspector
https://cnodejs.org/topic/5463f6e872f405c829029f7e
其实 webstorm,vs code 都支持的
12. 不太懂具体的应用场景,在多人合作的项目里这种构建工具应该什么时候执行呢?准备提测上线的时候统一执行一下?还是开发的过程中每一个人都在执行?如果不是每个人都即时在用的话,watch 存在的意义是什么呢?
看你的团队分工,是否真的前后端分离,如果不分离就每个人都的用,如果分离,前端组自动化生成的,放到 cdn 上,后端只要负责用就好了
watch 只在开发场景用,而且你看
npm install —save-dev gulp-xxx
13. 请问gulp和webpack区别和联系?
两者的功能是一样的,插件也都差不多,目前看到的区别都是使用方式、扩展等方面的
gulp 是标准、通用构建工具,上面基本都讲了,使用和定义、扩展都非常简单,比 webpack 简单的多
webpack 是新贵,支持 loader 和 plugin 机制,非常强大,而且可以把所有资源 bundle 到一起,目前 react、babel 等都使用其编译,其他细节,还需要研究,目前我了解的就这些
14. 请问 sourcemaps 是干嘛用的?
调试的,自己查
15. 请问推荐学习 stream 相关教程
文章中有讲到
https://github.com/substack/stream-handbook
有中文版的,自己搜吧
16. 桑大,流式和 buffer 的实际区别有哪些啊?没有使用过 buffer
不是一样的东西,buffer 可理解成把大象切块,放冰箱
流式,主要是 pipe 处理,多了事件监控而已,但底层也是用的 buffer 处理大文件的。
点击“阅读原文”可以跳转到桑世龙老师的github上浏览分享大纲。
以上是关于Gulp 实战和原理解析的主要内容,如果未能解决你的问题,请参考以下文章
如何用Diffusion models做interpolation插值任务?——原理解析和代码实战
Python开发实战资料分享:《Flask Web开发实战:入门进阶与原理解析》PDF+源代码
学习TF:《TensorFlow技术解析与实战》PDF+代码