ES6--Promise&模块化编程(详细解析!以及使用案例! 建议收藏!)

1. Promise的基本介绍

1. 传统的 Ajax 异步调用在需要多个操作的时候,会导致多个回调函数嵌套,导致代码不够
直观,就是常说的 Callback Hell。
2. 为了解决上述的问题, Promise 对象应运而生,在 EMCAScript 2015 当中已经成为标准
3. Promise 是ajax异步编程的一种解决方案。
4. 从语法上说, Promise 是一个 对象 ,从它可以获取异步操作的消息

2. 做一个Promise的应用案例

1. 首先创建monster.json

2. 创建monster_detail_1.json 

2.1. 用JQuery的Ajax解决 

先展示结果:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jquery-ajax</title>
</head>
<body>
<script src="jquery-3.6.0.min.js"></script>
<script>
  $(function () {
    $.ajax({
      url:"data/monster.json",
      //这里采用的是ES6方法简写的形式!
      success(data,status,xhr){
        console.log("第一次ajax请求访问的数据是=>",data)
          //在正确的基础上再次进行ajax请求
          $.ajax({
              url:`data/monster_detail_${data.id}.json`,
              success(data){
                  console.log("第二次访问ajax请求的数据=>",data)
              },
              error(error) {
                  console.log("error=>", error)
              }
          })
      },
      error(err){
        console.log("err=>",err)
      }
    })
  })
</script>
</body>
</html>

 出现的问题

不懂ajax的小伙伴可以去我的博客去看ajax    ajax

我们可以看出用$.ajax()方法,首先去拿去第一个json文件的数据,再根据第一个json文件的数据,去寻找第二个json文件,出现了回调函数嵌套的问题。虽然现在看起来没啥,但是如果嵌套多了,代码就会显得更加的冗杂,不易解读。

2.2. 用Promise的Ajax解决

先展示结果:

代码展示

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>使用promise完成多次ajax请求</title>
  <script type="text/javascript" src="jquery-3.6.0.min.js"></script>
  <script type="text/javascript">

    //先请求到monster.json
    //1. 创建Promise对象
    //2. 构造函数传入一个箭头函数
    //3. (resolve, reject) 参数列表resolve: 如果请求成功, 调用resolve函数
    //4. 如果请求失败, 调用reject函数
    //5. 箭头函数体, 仍然是通过jquery发出ajax
    let p = new Promise((resolve, reject) => {
      //发出ajax
      $.ajax({
        url: "data/monster.json",
        success(resultData) {//成功的回调函数
          console.log("promise发出的第1次ajax monster基本信息=", resultData);
          resolve(resultData);
        },
        error(err) {
          //console.log("promise 1发出的异步请求异常=", err);
          reject(err);
        }
      })
    })

    //这里我们可以继续编写请求成功后的业务
    p.then((resultData) => {
      //这里我们可以继续发出请求
      //console.log("p.then 得到 resultData", resultData);
      return new Promise((resolve, reject) => {
        $.ajax({
          url: `data/monster_detail_${resultData.id}.json`,
          success(resultData) { //第2次ajax请求成功,回调函数
            console.log("第2次ajax请求 monster的详细信息=", resultData);
            //继续进行下一次的请求
            resolve(resultData);
          },
          error(err) { //第2次ajax请求失败,回调函数
            //console.log("promise2 发出的异步请求异常=", err);
            reject(err);
          }
        })
      })
    }).then((resultData) => {

      console.log("p.then().then(), resultData", resultData)
      //即可以在这里发出第3次ajax请求=》 获取该妖怪的女友
      return new Promise((resolve, reject) => {
        $.ajax({
          url: `data/monster_gfd_${resultData.gfd}.json`,

          success(resultData) { //第3次ajax请求成功,回调函数
            console.log("第3次ajax请求 monster女友的详细信息=", resultData);
            //继续进行下一次的请求
            //resolve(resultData);
          },
          error(err) { //第2次ajax请求失败,回调函数
            //console.log("promise2 发出的异步请求异常=", err);
            //reject(err);
          }
        })
      })

    }).catch((err) => { //这里可以对多次ajax请求的异常进行处理
      console.log("promise异步请求异常=", err);
    })
  </script>
</head>
<body>

</body>
</html>

具体解读

1. 我们可以看出用Promise解决的callback hell的问题,因为他并没有嵌套,而是采用了一种类似的链式结构去执行。

2.从结构中解读

@1  里面就是new了一个Promise对象在括号里执行了箭头函数(参数名)=>(函数体),不熟悉的小伙伴可以看我的箭头函数的文档:箭头函数在第7

@2 函数体中和之前写$.ajax()的方法一样,但是不同的是在success过后如果你想要在进行ajax请求,并利用到上述的参数要resolve(resultData),其中resolve是参数名,这里显然是方法名(js的参数可以允许传入一个方法)。

@3 之后进行ajax请求用到p.then() ,再执行箭头函数

@4 你会发现我的代码在第三次ajax请求中有所不同,没有用一个变量来new Promise而是直接return,只是因为后续的请求中我的then也是连着写的,因为你return回去的就是一个Promise对象而then()方法也是Promise对象的

@5 reject()函数是错误的在当前错误的ajax请求中将错误信息进行抛出,Promise编程提供了一种统一的方法,用catch()直接捕获异常,但是reject你还是要写。

@6 每个方法的括号中都是执行的箭头函数

3.对Promise代码进行重排

上述代码看的出,虽然没有了嵌套调用,但是代码看起来还是很庞大,代码的复用性不高,很多代码都是重复的,所以我们可以将核心方法进行一个封装

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Promise代码重排</title>
  <script type="text/javascript" src="jquery-3.6.0.min.js"></script>
  <script type="text/javascript">
    function get(url,data) {
      return new Promise((resolve,reject)=>{$.ajax({
        url:url,
        success(resultData)
        {
          resolve(resultData)
        },
        error(err)
        {
          reject(err)
        }
      })})
    }
    //封装了核心代码后,在进行代码的重排
    get("data/monster.json")
            .then((resultData)=>{
      console.log("第一次发出ajax请求的数据=>",resultData);
      return get(`data/monster_detail_${resultData.id}.json`);
    }).then((resultData)=>{
      console.log("第二次ajax请求返回的数据=>",resultData)
      return get(`data/monster_gfd_${resultData.gfd}.json`);
    }).then((resultData)=>{
      console.log("第三次ajax访问数据=>",resultData);
    }).catch(err=>{
      console.log("错误的信息为:",err)})
  </script>
</head>
<body>

</body>
</html>

具体结果还是一样的。上述代码看起来就更加的简洁! 

4.模块化编程

1.   传统非模块化开发有如下的缺点: (1) 命名冲突 (2) 文件依赖 [ 代码演示 ]
2.  Javascript 代码越来越庞大, Javascript 引入模块化编程,开发者只需要实现核心的业务 逻辑,其他都可以加载别人已经写好的模块
3.  Javascript 使用 " 模 块 " module )的概念来实现模块化编程 , 解决非模块化编程问题

 

重点:在html静态文件中引入js是script的src属性引入,在js中引入另外一个js文件的内容用的是模块化编程 

4.1 ES5模块化编程(老版本) 

1. 每个 js 文件就是一个模块,有自己的作用域。在文件中定义的变量、函数、类 / 对象,
都是私有的,对其他 js 文件不可见
2. CommonJS 使用 module.exports={} / exports={} 导出 模块 , 使用 let/const 名称 =
require("xx.js") 导入模块

应用实例,进行分析 

1) 编写 functions.js , 该文件有函数 , 变量 , 常量 , 对象 , 数组。。。
2) 要求在 use.js , 可以使用到 function.js 中定义的 函数 / 变量 / 常量 / 对象

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.1415;
//定义对象
const monster = {
    name:"小牛",
    age:20,
    skill:"吃草",
    hi(){
        console.log("hi,我是小牛")
    }
}
//module的导出方式是以对象的形式进行导出
module.exports = {
    sub:sub,
    sum:sum,
    name:name,
    PI:PI,
    monster:monster
}

use.js 

//首先接收
const m = require("./function.js");
const {name} = require("./function.js")

//输出
console.log(m.sum(100,200));
console.log(m.sub(100,200));
console.log(m.monster.skill);
console.log(name);

具体解析 

@1 当一个js文件用另外一个js文件的数据时,另外一个文件需要用exports进行导出,导出的数据可任选,如上例所示,从语法格式来看,导出去的就是一个js对象

@2 当js文件用到另外一个js文件导出的数据时,需要用require()去接收,可以接收导出的所有的数据,用一个对象去接收,数据也是通过对象.属性名的情况访问。

@3 当然你一可以通过解构的形式,访问其中部分的数据比如const {属性名} = require(文件名)

@4 当exports导出的数据的属性名和value值同名时,可以省略属性名

4.2 ES6模块化编程(新版本)

依然使用ES5中的案例

1 ES6 使用 (1) export { 名称 / 对象 / 函数 / 变量 / 常量 } (2) export 定义 = (3) export default {}
导出模块
2 、使用 import {} from "xx.js" / import 名称 form "xx.js" 导入模块

使用第一种方式 

common.js

//定义对象,变量,常量, 函数
const sum = function (a, b) {
    return parseInt(a) + parseInt(b);
}

const sub = function (a, b) {
    return parseInt(a) - parseInt(b);
}

let name = "ddd";

const PI = 3.14;

const monster = {
    name: "牛魔王",
    age: 500,
    hi() {
        console.log("hi 你好 牛魔王");
    }
}

//es6的导出模块/数据
/**
 * 1. export 就是导出模块/数据
 * 2. 可以全部导出,也可以部分导出
 */
export {
    sum,
    sub,
    name,
    monster
}

use_common.js

//导入
/**
 * 1. 我可以{} 来接收导出的数据
 * 2. 可以全部接收,也可以选择的接收
 * 3. 细节: 这时要求导入的名称和导出的名称一致
 */
import {sub,sum,name} from "./common";
import {monster} from "./common";

//使用
console.log(sumx(10, 90));
console.log(name);
console.log(monster.hi())

使用第二种方式 

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 = "dd";

const PI = 3.14;

const monster = {
    name: "牛魔王",
    age: 500,
    hi() {
        console.log("hi 你好 牛魔王");
    }
}

use_common2.js

//可以导入模块/数据
import {sum}  from "./common2";
//没有导出的数据, 是不可以导入
//import {sub}  from "./common2";

console.log(sum(10,30));

使用第三种方式 

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));

注意事项 

1. ES6 的模块化无法在 Node.js 中执行,需要用 Babel 转码 ES5 后再执行
2. export 不仅可以导出对象,一切 JS 变量都可以导出。比如:基本类型变量、函数、数
组、对象
3. 没有导出的不能使用
4. es6 有导出方式较多 , 不同的导出方式对导入方式 也有一定影响

本篇文章通过b站韩顺平教育学习可得,如有侵权地方,立即删除

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值