java(抓哇烧烤)学习 前端技术栈:【2】-Promise&模块化编程

1.Promise对象

解释:Promise 是 JavaScript 中的一个对象,它代表了一个异步操作的最终完成或失败。

(1)出现原因

因为传统的Ajax请求,会出现一个情况:就像很多个if语句嵌套,导致代码的可读性很差不够直观。

NPC个人理解:类似于我们数据库里面请求打过去拿到一张表里面的  id值,但是不是立即返回这个请求,还要继续根据这个  id 值去 查询到另外一张表里面的  id,有点像主键和外键一样,但是一旦我发送的请求不是一两个,可能请求总个数到达:5,6,7,8,9,到最后面再一层层返回,这样就会导致代码有很多个回调函数嵌套了 ,如下面代码

$.ajax({//第一层Ajax请求
    url: '/data1',
    success: function(data1) {
        console.log('Data 1 received:', data1);

        $.ajax({//第二层Ajax请求
            url: '/data2',
            success: function(data2) {
                console.log('Data 2 received:', data2);

                $.ajax({//第三层Ajax请求
                    url: '/data3',
                    success: function(data3) {
                        console.log('Data 3 received:', data3);

                        // 处理所有数据的逻辑
                        processAllData(data1, data2, data3);
                    },
                    error: function(xhr, status, error) {
                        console.error('Error fetching data 3:', error);
                    }
                });//第3层完成返回
            },
            error: function(xhr, status, error) {
                console.error('Error fetching data 2:', error);
            }
        });//第2层完成返回
    },
    error: function(xhr, status, error) {
        console.error('Error fetching data 1:', error);
    }
});//第1层完成返回

function processAllData(data1, data2, data3) {
    // 在这里处理从三个 AJAX 请求获取的所有数据,
//类似于我上面说的数据库里面一张表 关联 另外一张表,然后进行Ajax嵌套
    console.log('Processing all data:', data1, data2, data3);
}

(2)原始的Promise代码:

从上面看的Ajax嵌套来看,代码直观性很差,这种情况的出现也就引出了:promise

类似于函数的调用链了,避开了嵌套,代码如下:

   let p = new Promise((resolve,reject)=>{
            $.ajax({
                //相对路径: ./表示当前目录,  ../表示上层目录, 可以多次使用../
                url : "../data/Me.json",
                success(reslutData){//resultData就是Ajax返回的数据本身
                    console.log(reslutData);
                    // 这里别写成:resolve.resultData
                    //这句话类似于开关,让我们执行成功之后,继续发送请求的开关
                    resolve(reslutData);
                },
                error(err){//err同理也是Ajax返回的数据本身
                    console.log(err);
                    reject(err); // 添加 reject(err) 语句
                }
            })
        })



        p.then((resultData)=>{//上一个promise对象success后,需要执行的代码
            //注意这里要有return,否则下面的catch里面的代码无法执行
            return new Promise((resolve,reject)=>{
                $.ajax({     //这里故意让请求的URL写错,让return之后将错误能够正确被捕获
                    url : `../dat1a/Me_${resultData.id}.json`,
                    success(reslutData) {
                        console.log(reslutData);
                        resolve(resultData);
                    },
                    error(err) {
                        console.log(err);
                        reject(err); // 添加 reject(err) 语句
                    }

                })
            })

        })
        .catch((err) => {
                console.log("catch语句捕获到了:", err);
            })

resolve(resultData):这个语句用于在 Promise 中成功地完成一个异步操作,相当于是一个开关,有它才会执行  then语句。

Promise 链中的 then() 方法是接收resultData 数据,并对其进行进一步的处理。

reject(err):这个语句用于在 Promise 中发生错误时,通知 Promise 链中的 catch() 方法。其进行进一步的处理

(3)为什么要return   promise对象?

现象:当有两个Ajax请求或者 更多的时候,第二个Ajax请求要是不 return,就不会执行catch里面的代码:

原因:

  • return:新创建的 Promise 被返回并添加到 Promise 链中,错误会沿着链向下传播,最终被 catch 方法捕获。
  • 没有 return:新创建的 Promise 没有被返回,对Promise 链没有任何影响,错误也不会顺着链传播,因此 catch 方法不会捕获到这个错误。

(5)promise之代码重排

     于晏人话:就是对promise进行了一定的封装优化,这一次就非常直接和清晰了

学到后边,但是发现这样的promise链式调用,还是有点点复杂,但是相比于原来的Ajax嵌套好太多,为了更好的使用promise链式调用,于是就出现了promise代码重排,目的就是让代码:更直观,可读性会更好:

我们看上面的每一次promise的  Ajax请求   里面有很多的代码是重复的,代码冗余

我们明白用promise发起Ajax请求的结果,就是为了拿到一个promise对象?

所以就有了一个思路:我们将这个得到promise对象的过程,封装成一个方法。如下:

 
 //自己封装一个方法,目的就是为了得到一个promise对象 function get(url,data){
   function get(url,data){
        return new Promise(
            (resolve,reject)=>{
                   $.ajax({
                         url : url,
                         data : data,
                         success(resultData){
                         resolve(resultData);
                           },
                         error(err){
                         reject(err);
                           }
                     })
              })
         }
    

   下面就是在封装的基础上实现发送多次请求:

(其实也不高级,就是为了让我们方便看,直观地去处理业务逻辑)


        // 个人理解的模版:
        //promise是then方法的调用者,
        // 其中resultData当前promise携带的数据
        // 在then方法内部继续创建promise对象,并传递(return)
 get("../data/Me.json").then(
            (resultData)=>{
                console.log(resultData);//打印第一次请求的数据,并返回第二次的Ajax请求的promise对象
                return get(`../data/Me_${resultData.id}.json`);
            }//得到新的promise对象

 ).then(
            (resultData)=>{
                console.log(resultData);//打印第2次请求的数据,并返回第3次的Ajax请求的promise对象
                return get(`../data/Me_${resultData.friend_id}.json`);
            }

 ).then(
            (resultData)=>{
                console.log(resultData)//打印第3次请求的数据
            }
 )

浏览器里面控制台输出的结果:

2.模块化编程

只介绍两个时期的:一个ES5, 一个ES6的

模块化编程的人话理解:类似于封装  java  一个类里面的所有属性,到另外一个类里面去用,

场景:当我们有多个js文件一号js文件需要调用2号js文件里面的:对象、变量、常量、函数,

类比:html文件里面     使用js文件里面的东西:

本质把一个js文件封装成对象,最后在另外一个js文件里面 拿这个对象来使用(个人理解,狗头保命= 。=)

看代码:

<1> ES5模块化的两句重要代码:

导出和导入

(1)导出的代码:

三种方式很简单(最后一种是可以取别名的方式)

module.exports = {
    Me,
    YOU,
    Me_words,
    You_words,
    add
};

//或者这样,两种方式都可以写,少了个module
exports = {
    Me,
    YOU,
    Me_words,
    You_words,
    add
};

//第三种:如果导出的时候想要取一个自己  应用的别名:
exports = {
    别名1:Me,
    别名2 :YOU,
    me_words :Me_words,
    you_words :You_words,
    sum : add
};
(2)导入的代码:
const Dui_Xiang = require("./A");

//模版:const 对象名 = require("引入的js文件路径");
(3)只导出某一部分属性

如果只是想要导出某一部分属性(不想导出全部):

导出端:

module.exports = {
  Me,
  You_words,
  add
};

接收端:

const { Me, You_words, add } = require("./A");

相对而言很灵活的:自己别太笨,看情况使用就行

<2> ES6模块化导出导入:

ES6的导出也是有三种方式:

(1)第一种:批量导出+导入

其实我个人觉得和ES5的没什么区别,就是关键字变了变成export,用法都一样

export {//ES5的是module.exports{} 或 exports{}
 PI, 
 E,
 add,
 subtract,
 Calculator 
};

批量导出对应的  导入

(代码最后是对应,怎么使用该属性的格式)

import {PI, E, add } from 'js文件路径';
//如果对方  导出了 三个属性,
//  导入这边   也可以选择性接受一个或者两个,不用全部接受


//导入进来属性使用的格式:
console.log(PI); 
console.log(E); 
console.log(add(2, 3));
(2)第二种:直接导出+导入

 人话:刚定义好,我就给你导出了

代码如下:

//在我定义语句前面  直接 + 一个export,
//相当于然后那个变量  “直接导出”
//只有写了export 的那些变量会被导出,其余无影响
export const PI = 3.14159;

export function add(a, b) {
  return a + b;
}

对应的导出代码:(其实和上面第一种导出方式很像,只是这个你要与导出的属性对应【属性名也要相同哈,别自己取名字,彦祖!】,不要多,也不要少)

import { PI, add } from 'js文件路径';

console.log(PI); 
console.log(add(2, 3)); 
(3)第三种:默认导出+导入

人话+个人理解:这个就是把要导出的属性  包装成一个 对象,通过这个对象来取属性,这个导出类似于ES5里面的导入

//默认导出:导出了一个对象(导入的时候自己取名)
//这个对象里面有  add,subtract两个方法
export default {
  add(a, b) {
    return a + b;
  },
  subtract(a, b) {
    return a - b;
  }
};

导入代码:

//默认的导入
import 自定义的对象名 from 'js文件路径';


//使用属性的格式:
console.log(自定义对象名.add(2, 3)); // Output: 5
console.log(自定义对象名.subtract(5, 3)); // Output: 2

注意细节补充:

1.ES6的模块化不能在Node.js中执行,要先用Babel转码成ES5之后才可以进行处理
2.export 不仅可以导出对象,比如:基本类型变量、函数、数组、对象都可以导出
3.es6有导出方式较多,不同的导出方式对导入方式也有一定影响

 

  • 33
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值