开课吧前端1期.阶段5:generator,模块化与babel
复习:ES6 变量let、箭头function、参数等、map、reduce、filter、forEach Promise消除回调,Promise.all([p1,p2,p3]).then() 单独Promise并不能帮我们解决所有问题,还有2个兄弟是从Promise过度出来的,generator ,async* generator ,async* 严格来说是属于ES7的东西
//generator怎么去用,先抛弃不要想Promise
generator 翻译:生成器
generator -- 特殊的函数
普通函数 --》 【开始执行,一路到底】 ---》飞机(没法停)
generator 函数 --》 【中间能停】 , 踹一脚走一步 --》出租车(随时可停)
//普通函数-无法中间停
<script>
function show(){
alert('a');
//想中间停
alert('b');
}
show();
</script>
//中间可以停
<script>
function *show(){ //generator特点:星号*
alert('a');
yield; //告诉在哪停
alert('b');
}
let obj = show(); //执行完并不会执行函数代码,会生成generator对象
obj.next(); //简单理解踹一下走一下,走到第一个yield停住,//alert:a
obj.next();//alert:b
</script>
yield可以: 1、传参 2、有返回值【可以阶段性传参】 作用:类似炒菜过程

<script>
function *show(){
alert('a');
yield 12;
alert('b');
return 5;
}
let obj=show();
let res1=obj.next(); //{value: 12, done: false} //done有没有完成
console.log(res1);
let res2=obj.next(); //{value: 5, done: true}
console.log(res2);
</script>
//传参
<script>
function *show(a,b){
alert('a');
console.log(a,b);
let c=yield;
console.log(c);
alert('b');
return 5;
}
let obj=show(12, 5);
let res1=obj.next();//undefine 第一次next没有结果【下图理解】
let res2=obj.next(888);
</script>

为什么好好函数?中间需要停一下?,例如:生活打车为什么中间要停一下【接人,忘了东西】
程序中为啥要停一下,等待某些操作结束,例如:数据交互。
function *show(){
xxx
xxx
let data1 = yield $.ajax('a.text')
xxx
xxx
let data2 = yield $.ajax('b.text')
xxx
xxx
}
比方说我有个函数,等待a请求的ajax结束,然后收集数据data1,等下下一个b的ajax请求,我们知道generator函数走到yield要暂停,next()往下执行。但是我们是否可以通过同步写法,完成异步的操作?
需要辅助工具
node小工具
安装cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm search yield-runner-blue //跳出网页,搜索yield-runner-blue
cnpm i yield-runner-blue //安装 install
//会在当前cmd路径下,有个node_modules/yield-runner-blue 文件夹
//演示,runner封装特点:即享受到异步带来的性能优势,同时兼顾到了你写代码的习惯
<script src="runner.js" charset="utf-8"></script>
<script src="jquery.js" charset="utf-8"></script>
<script>
//generator函数不能用箭头函数
runner(function *(){
alert('欢迎哈');
//等下数据结束,什么时候结束什么时候往下执行
let arr=yield $.ajax({url: 'data/1.txt', dataType: 'json'});
alert('接收到了数组'+arr);
let json=yield $.ajax({url: 'data/2.txt', dataType: 'json'});
alert('json也读完了');
console.log(json);
});
作业1:看懂runner.js [yield-runner-blue的index.js]
作业2:搞懂传统的ajax请求和generator区别,优缺点
演示中的generator,需要依赖一个runner.js
既然generator那么好用,ES7官方也出一个runner【async/await】
既然runner.js那么好用,官方为啥不出一样
es7出了一个叫做: async / await
<script>
async function show(){
alert('欢迎哈');
let arr=await $.ajax({url: 'data/1.txt', dataType: 'json'});
alert('接收到了数组'+arr);
let json=await $.ajax({url: 'data/2.txt', dataType: 'json'});
alert('json也读完了');
console.log(json);
}
show(); //函数调用
</script>
<script>
//省略,箭头函数
(async ()=>{
alert('欢迎哈');
let arr=await $.ajax({url: 'data/1.txt', dataType: 'json'});
alert('接收到了数组'+arr);
let json=await $.ajax({url: 'data/2.txt', dataType: 'json'});
alert('json也读完了');
console.log(json);
})();
</script>
总结:
Promise本质:等待异步操作结束
generator本质:无感处理异步操作
async本质:官方runner
runner(function *(){
xxx
let 结果1 = yield 异步操作1
xxx
let 结果2 = yield 异步操作2
xxx
});
(async function(){ //可写 async ()=>
xxx
let 结果1 = await 异步操作1
xxx
let 结果2 = await 异步操作2
xxx
})()
模块【引入一个第三方登陆模块】 或等于 【元件】 或等于 【组件】 (一个东西) 1. 民间版的-sea.js , require.js CMD,和 AMD 模块的规范 *作业3: 找找CMD和AMD是什么,区别? 2. nodejs模块化 3. ES6模块化 【官方出来以后,大家抛弃了民间】
sea.js使用
bower i seajs 【官网打不开,下载一个】 模块是什么?就是一个可以重复使用单位 模块分为2个部分: 1.定义 2.调用 ----sea.js的模块使用 sea好处: 按需引用,解决依赖
//mod1.js
//exports 导出 [对外导出a和b]
//模块是被包起来的,需要写在define内部
define(function(require, exports, module)){ //define是有参数的
exports.a=12;
exports.b=5;
exports.calc=function (){ } //函数外部出口
//module作用:批量导出
module.exports={
a: 12, b: 5,
show(a, b){
alert(a+b);
}
};
//require 用来引用其他模块
})
//直接定义是无法使用的,只能在内部,作用域
//let a=12;
//let b=5;
//1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!--
不能这么使用,不然失去模块化的意义
<script src="mod1.js" charset="utf-8"></script>
-->
<script src="sea.js" charset="utf-8"></script>
<script>
seajs.use(['mod1.js'], function (mod1){ //use引用模块
//回调函数
mod1.show(mod1.a, mod1.b);
});
</script>
</head>
<body>
</body>
</html>
//总结:
//1.定义模块 mod1.js
define(function(require,exports,module){
exports.a=12;
exports.b=5;
});
//2.引用模块 1.html
seajs.use(['xxx.js','bbb.js'],function(mod1){})
//ES6的JSON的,key和value一样,可以简写
let a=12;
let b=6;
let json={a,b};
//函数可以缩写
{
show:function(){} //原来写法
show(){} //新写法
}

-- mod2.js
define(function (require, exports, module){
let moda=require('./a.js');
let modb=require('./b.js');
exports.res=moda.num1+modb.num2;
});
-- 2.html
<script src="sea.js" charset="utf-8"></script>
<script>
seajs.use('mod2',function (mod){
alert(mod.res); //
});
</script>
seajs和require.js 本身消息了,但是这种用法还是存在的,只不是在node.js上体现 如果我是拿着html去找js,使用:use 如果在js文件里面再去找js,使用:require 在node.js里面没有use,只有require,因为都是js找js
//3.js //define() ,原来是要使用define,现在不需要了 exports.a=12; //输出a:12
//2.js exports.b=55; //输出b:55
//1.js
let mod2 = require('./2');//.js可以省略,同名js使用直接使用名字:2.js = 2
let mod3 = require('./3.js');
console.log(mod2.a+mod3.b);

//seajs里面
define(function(){
let moda = require('./a');
let modb = require('./b');
//可以把.点给去掉,是一样的,可有可无
let moda = require('a');
let modb = require('b');
});
//node.js里面
let mod2 = require('2');
let mod3 = require('3.js');
//报错
//Cannot find moudle '2'
//为什么: 在reajs,require.js里面只有你定义的的模块,没有别人的模块,而node.js不一样,包含有系统模块,再带的模块,http等
let http=requier('http'); //引用系统模块
console.log(http);
let http2=requier('./http'); //引用自定义模块, ./表示在当前文件夹下查找http.js
console.log(http2);
//node_modules
//想引用自己的模块,但是每次都要加【./】好麻烦,可以有一个文件夹【node_modules】,这个名字不能乱动,不能改,必须叫这个,因为默认会去这里面找东西。
let mod2 = require('2'); //这时候不带./也能出来
let mod3 = require('3.js');
console.log(mod2.a+mod3.b); //正常输出:67
node的模块化 1.没有define 2.exports,require,module 3.引用自定义模块 放到node_modules里 前面加./
--创建自己的包,发布给别人用
--node的东西习惯前面有个nmath,用于区别系统的math
1.创建文件夹 nmath
2.创建包信息 npm init
--pack name(nmath)
--description: this is my math package【输入描述】
--entry point: a.js 【入口文件,当别人引用你包时候,到底引用是谁】
--test command: 【你做出来东西,有相应的测试,帮你来测试的命令】
--git repository: 【托管的地址】
--keywords: math my【便于别人搜索】
--author: lisi 【作者是谁】
--license: (ISC): 【许可】
-- is this ok ?
//生成package.json
{
"name": "nmath",
"version": "0.0.1",
"description": "this is my math package",
"main": "a.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"math",
"my"
],
"author": "lisi",
"license": "ISC"
}
//a.js 入口
module.exports={
sum(a,b){ //加法
return a+b;
},
divide(a,b){ //除法
return a/b;
}
};
3.把你的包放到node_modules
4.使用require('nmath') //加载
//test_nmath.js
const nmath=require('nmath'); //相当于require('a.js')
console.log(nmath.divide(12, 66));
5.执行测试
node test_nmath
//让全世界都用上你的包, 发布你的包
6.npm publish
--错误:err! code e403,verify your email 【先验证你的邮箱,先登陆】
--登陆:npm login 【会传到官网: www.npmjs.com】
--再次 npm publish
ES6模块和Node区别
ES6模块化:首先官方提供的,首先用官方的,一个性能好,一个统一标准 ES6出了2个新东西:import、export 原来民间版本不是叫:require,现在ES6官方叫:import //官方语法解释怎么用 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export

//1.js
let a=12; //不输出是用不了的
let b=5;
export{a,b}
//import.html
<script>
import mod1 from "./1.js"
alert(mod1.a); //Unexpected token import 目前浏览器还不是很支持ES6模块化 import
alert(mod1.b);
</script>
//目前浏览器不是很支持ES6模块化,有没有什么办法?
//靠工具来帮我们,ES6尽管是官方的,还是需要工具的支撑
1、ES6---目前没法浏览器用--可以用babel编译,babel可以编译普通JS代码,但是无法编译es6模块,编译模块需要WebPack
2、WabPack
//语法不同
Node:
输出
exports.a=12;
module.exports={x, x, x};
引入
let mod=require('./aaa.js');
ES6:
输出
export {x, x, x};
引入
import mod from "./xxx.js" //加了mod可以直接用
babel不能编译模块,但是能编译ES6,可以帮助我们理解工具如何用
babel官网: https://babeljs.io/

//如何使用babel
1、.安装babel-cli
cli全称:command line interface //命令行接口
build: babel src -d lib == npm run build
npm i -g babel-cli //全局安装
2、在文件夹编译,创建文件夹babel_es6
//创建 1.js 文件, 大量用到es6特性
let a=12;
const b=5;
let arr=[{a, b}, {b, a}];
arr.sort((json1, json2)=>json1.a=json2.a);
alert(arr[0].a);
//1.html,在谷歌浏览器Chrome可以运行,在IE11浏览器无法运行
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/1.js" charset="utf-8"></script>
</head>
<body>
</body>
</html>
//2.由于IE无法运行,需要编译
//3.进入目录babel_es6
npm init //建立一个package.json,就是工程文件
//需要在scripts加一个build,目前我们暂时用不到,但是后面用到很多
"scripts": {
"build": "babel js -d build"
}
//script用处:保存写好的命令,不用每次都打
//假如我们在命令行输入命令: node server.js --slience --no-err --report=c:/a.txt
//正常启动 server.js 我需要在后面带一堆的参数,每次都要写那么多参数累死了。所以可以在
//script里面加名字,例如:serv
"scripts": {
"serv": "node server.js --slience --no-error --report=c:\\a.txt"
}
//运行的时候就可以:npm run 【npm run 这2个是固定的】
// npm run serv 【效果等同于node server.js --slience --no-error --report=c:\\a.txt】
//4.运行试试
babel js -d build //在js里面夹里面变异js文件到build文件夹
//执行后会生成build文件夹,存放处理后js文件
//报错:Error: Couldn't find preset "env" relative to directory
//需要安装安装babel-preset-env,同样是在项目的根目录下通过以下命令行安装:
//npm install -D babel-preset-env
//5.然后运行 npm run build 或者 babel js -d build
js\1.js -> build\1.js //成功后,1.js文件变成了,bulid/1.js
//6.运行成功后,发现js文件内容没有什么变化,除了整齐点
//7.创建 .babelrc 配置文件
{
"presets": ["env"] //presets预设,说白了babel需要大量选项需要配置,我听谁的,是你一个个给我,还 //是我默认去找一个叫做env的,说明babel有很多种模式,env就是其中一种
//安装npm install babel-preset-env --save-dev
//--save-dev 就等于 -D ,开发环境依赖
//--save 是生产环境依赖
}
//8.package.json 文件变化,增加了devDependencies
"devDependencies": { //dev开发,devDependencies依赖: 开发模式的依赖的模块
"babel-preset-env": "^1.7.0"
}

babel编译模块
文件夹结构:
/js/mod/m1.js
/js/mod/m2.js
/js/2.js
//m1.js
let a=12;
export {a};
//m2.js
let b=12;
export {b};
//2.js
import m1 from "./mod/m1.js"
alert(m1.a);
//编译模块
npm run build
//编译完后/build/2.js,内容
"use strict";
var _m = require("./mod/m1.js");
var _m2 = _interopRequireDefault(_m);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
alert(_m2.default.a);
//出现了require,我们知道require原生JS无法使用。其实babel直接编译export,import作用不明显,看不到效果,还是需要搭配其他工具。
1、看yield-runner
2、看AMD和CMD的区别
3、尝试webpack编译import 和 export
浙公网安备 33010602011771号