一、promise
1 Promise 基本介绍
- 传统的 Ajax 异步调用在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够直观,就是常说的 Callback Hell
- 为了解决上述的问题,Promise 对象应运而生,在 EMCAScript 2015 当中已经成为标准 Promise 是异步编程的一种解决方案。
- 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息
- 一句话: Promise 是异步编程的一种解决方案, 可以解决传统 Ajax 回调函数嵌套问题
2 应用实例
2.1 需求分析/图解
2.2 代码实现
2.2.1 json
创建 D:\idea_java_projects\es6\promise\data\monster.json
创建 D:\idea_java_projects\es6\promise\data\monster_detail_1.json
2.2.2 使用 ajax 传统方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jquery-ajax多次请求</title>
<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$.ajax({
url:"data/monster.json",
success(resultData){
console.log("第一次ajax请求,我们拿到了monster基本信息=",resultData);
//进行第二次请求,此时就出现了ajax的嵌套
$.ajax({
url: `data/monster_detail_${resultData.id}.json`,
success(resultData) {
console.log("第二次ajax请求,我们拿到了monster详细信息=",resultData);
},
error(err) {
console.log("第二次出现异常=",err)
}
})
},
error(err){
console.log("出现异常=",err)
}
})
</script>
</head>
<body>
</body>
</html>
2.2.3 使用 promise 方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用promise完成多次ajax请求</title>
<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
//先请求到monster.json
let p =new Promise((resolve,reject)=>{
//创建promise对象需要传入一个箭头函数
//(resolve,reject)参数列表,如果请求成功调用resolve函数,失败调用reject函数
//箭头函数体仍然是通过jquery发出ajax
//发出ajax请求
$.ajax({
url:"data/monster.json",
success(resultData){
console.log("promise发出的第一次ajax monster的基本信息=",resultData);
resolve(resultData);
},
error(err){
//console.log("promise发出的异步请求出现错误=",err)
reject(err);
}
})
})
//这里我们可以继续编写请求成功后的业务
p.then(resultData=>{
console.log("p.then得到了resultData",resultData);
return new Promise((resolve, reject) => {//如果没有return 那么这里的error捕获不到给p
$.ajax({
url: `data/monster_detail_${resultData.id}.json`,
success(resultData) {
console.log("promise发出的第二次ajax monster的详细信息=",resultData)
resolve(resultData)
},
error(err) {
//console.log("promise第二次发出的异步请求出现错误=",err)
reject(err)
}
})
})
}).then((resultData=>{
console.log("p.then().then,resultData",resultData)
//可以在这里发出第三次请求
}))
.catch(err=>{//这里可以对多次ajax的异常进行处理
console.log(err)
})
</script>
</head>
<body>
</body>
</html>
2.2.4使用 promise 代码优化/重排
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>promise 代码重排</title>
<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
/**
* 这里我们将重复的代码,抽出来,编写一个方法 get *
* @param url ajax 请求的资源
* @param data ajax 请求携带的数据
* @returns {Promise<unknown>}
*
* */
function get(url,data) {
return new Promise((resolve, reject) => {
$.ajax({
url:url,
data:data,
success(resultData){
resolve(resultData);
},
error(err){
reject(err);
}
})
})
}
//需求
//先获取monster.json
//获取monster_detail1.json
//进入第三次
get("data/monster.json").then(resultData=>{
//第一次ajax成功后的处理位置
console.log(resultData);
return get(`data/monster_detail_${resultData.id}.json`);
}).then(resultData=>{
//第二次成功后的处理代码
console.log("第二次成功后的结果=",resultData);
//如果还需要下一把
//return get(url,data)以此类推
}).catch(err=>{
console.log(err);
})
</script>
</head>
<body>
</body>
</html>
2.2.5 注意事项和使用细节
- 如果返回的是 Promise 对象,可以继续执行.then()
- .then((data)=>{}) 的 data 数据是上一次正确执行后 resolve(data) 返回传入的
- 通过多级.then() 可以对异步请求分层次请求,实现代码重排,代码逻辑更加清晰合理
- 通过多级.then() 后面的 .catch((err) => {}) 可捕获发生异常,便于调试
3 Promise 课后练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>homework</title>
<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
function get(url,data) {
return new Promise((resolve, reject) => {
$.ajax({
url:url,
data:data,
success(resultData){
resolve(resultData);
},
error(err){
reject(err);
}
})
})
}
get("data/student_100.json").then(resultData=>{
console.log("第1=",resultData);
return get(`data/class_${resultData.class_id}.json`);
}).then(resultData=>{
console.log("第2=",resultData);
return get(`data/school_${resultData.school_id}.json`);
}).then(resultData=>{
console.log("第3=",resultData);
}).catch(err=>{
console.log(err);
})
</script>
</head>
<body>
</body>
</html>
二、模块化编程
1介绍
1.1基本介绍
- 传统非模块化开发有如下的缺点:(1)命名冲突 (2)文件依赖[代码演示]
- Javascript 代码越来越庞大,Javascript 引入模块化编程,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块
- Javascript 使用"模 块"(module)的概念来实现模块化编程, 解决非模块化编程问题
- 模块化 也是 ES6 的新特性
1.2 示意图
1.3 模块化编程分类
- CommonJS 模块化规范/ES5 的写法
- ES6 模块化规范
2 CommonJS 模块编程
2.1 介绍
- 每个 js 文件就是一个模块,有自己的作用域。在文件中定义的变量、函数、类/对象,都是私有的,对其他 js 文件不可见
- CommonJS 使用 module.exports={} / exports={} 导出 模块 , 使用 let/const 名称 = require("xx.js") 导入模块
2.2 应用实例
2.2.1 需求说明
- 编写 functions.js , 该文件有函数,变量, 常量, 对象, 数组。。。
- 要求在 use.js , 可以使用到 function.js 中定义的 函数/变量/常量/对象
- 请使用模块化编程的方式完成, 尽量将各种写法都写一下
2.2.2 思路分析/图解
2.2.3 代码实现
function.js
//定义对象,变量,常量,函数
const sum=function (a,b) {
return parseInt(a)+parseInt(b);
}
const sub=function (a,b) {
return parseInt(a)-parseInt(b);
}
let name="林然";
const PI=3.14;
const monster={
name:"牛魔王",
age:500,
hi(){
console.log("我是牛魔王,你好");
}
}
//导出
/*
1. module.exports 导出模块
2. 把你需要导出的数据, 写入到 {}中即可
3. 可以全部导出,也可以部分导出
4. 理解:相当于把我们导出的数据,当做一个对象
5. 如果属性名和函数/变量/对象..名字相同,可以简写
6. 有些前端, 简写 module.exports={} 成 exports={}
*/
module.exports={
sum:sum,
sub,//简写
myname:name
}
use.js
//导入
//1. 在 es5 中, 我们通过 require 就包 对应.js 中的
//数据/对象,引入
//2. 我们使用的时候,通过 m.属性 就可以使用
//3. 如果我们导入时,不需要所有的,可以导入部分数据
const m=require("function");
console.log(m.myname);
console.log(m.sub(2,3));
//3. 如果我们导入时,不需要所有的,可以导入部分数据
const {sub,sum} =require("./function");
console.log(sub(1,3))
console.log(sum(1,3))
要看运行效果,需要
Node
环境
, node
环境我们后面搭建
,
只要
use.js
可以解析
sum
和
sub
说明是正确的
3 ES6 模块编程
3.1 介绍
- ES6 使用 (1)export {名称/对象/函数/变量/常量} (2) export 定义【对象】 ={} (3) export default {}
- 导出模块
- 使用 import {} from "xx.js" [对应(1)(2)]/ import 名称 form "xx.js" 导入模块
3.2 应用实例-批量导出形式
3.2.1 需求说明
- 编写 common.js , 该文件有函数,变量, 常量, 对象
- 要求在 use_common.js , 可以使用到 common.js 中定义的 函数/变量/常量/对象
- 请使用 ES6 模块化编程的方式完成
3.2.2 思路分析/图解
common.js
//定义对象,变量,常量,函数
const sum=function (a,b) {
return parseInt(a)+parseInt(b);
}
const sub=function (a,b) {
return parseInt(a)-parseInt(b);
}
let name="林然";
const PI=3.14;
const monster={
name:"牛魔王",
age:500,
hi(){
console.log("我是牛魔王,你好");
}
}
//es6 的导出模块/数据
/**
* 老师解读
* 1. export 就是导出模块/数据
* 2. 可以全部导出,也可以部分导出
*/
export {
sum,
sub,
name
}
use_common.js
//导入
/**
*
* 1. 我可以{} 来接收导出的数据
* 2. 可以全部接收,也可以选择的接收
* 3. 细节: 这时要求导入的名称和导出的名称一致
*/
import {sum,name,sub} from "./common"
console.log(name);
3.3 应用实例-其它导出形式
common2.js
//定义对象,变量,常量,函数
//定义对象,变量,常量, 函数
//定义 sum 函数时,就直接导出
//如果在定义时,导出的数据, 在导入时,要保持名字一致
export const sum=function (a,b) {
return parseInt(a)+parseInt(b);
}
const sub=function (a,b) {
return parseInt(a)-parseInt(b);
}
let name="林然";
const PI=3.14;
const monster={
name:"牛魔王",
age:500,
hi(){
console.log("我是牛魔王,你好");
}
}
//es6 的导出模块/数据
/**
* 老师解读
* 1. export 就是导出模块/数据
* 2. 可以全部导出,也可以部分导出
*/
export {
sum,
sub,
name
}
use_common2.js
//导入
/**
*
* 1. 我可以{} 来接收导出的数据
* 2. 可以全部接收,也可以选择的接收
* 3. 细节: 这时要求导入的名称和导出的名称一致
*/
import {sum} from "./common2"
console.log(sum(1,3));
common3.js
//定义对象,变量,常量, 函数
//演示默认导出
//如果是默认导出, 导入的时候,使用的语法
//可以这里理解, 类似把 {} 当做一个对象导出
export default {
sum(a,b) {
return parseInt(a) + parseInt(b);
},sub(a,b) {
return parseInt(a) - parseInt(b);
}
}
use_common3.js
//导入默认导出模块/数据
//好处是 m 名称是可以自己指定的.
//因为 m 名字, 程序员可以自己指定,因此我们就可以解决名称冲突问题
import m from "./common3";
//使用 m.xx
console.log(m.sub(80,90));
3.4 注意事项和使用细节
- ES6 的模块化无法在 Node.js 中执行,需要用 Babel 转码 ES5 后再执行
- export 不仅可以导出对象,一切 JS 变量都可以导出。比如:基本类型变量、函数、数组、对象
- 没有导出的不能使用
- es6 有导出方式较多, 不同的导出方式对导入方式也有一定影响