Promise 尚硅谷笔记

458 阅读13分钟

超级重要 面试必备

可恶 其实主要就是想学那个asyncawait 发现自己什么都不会

image.png

🍔正文开始啦 !!!

Promise的理解和使用

1、概念

通俗来说 Promise是一个承诺 承诺的事情不一定可以完成 但是会返回一个结果

  • pending 正在做。。。
  • Resolve 完成这个承诺
  • Reject 失败了

2、特点:

(1)只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。

3、缺点:

(1)无法取消Promise,一旦新建它就会立即执行,无法中途取消。和一般的对象不一样,无需调用。

(2)如果不设置回调函数,Promise内部抛出的错误,不会反应到外部

(3)当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

什么是Promise ?

其实就是JS中对于 进行异步编程的新解决方案

之前的解决方案是 单纯的使用回调函数

关于异步操作

首先先了解一下并行 并发 同步和 异步

1. 并行

就是指计算机可以同时执行多个任务 进程或者上下文切换

2. 同步和异步

同步: 任务完成才可以执行下一个任务

异步: 各个任务之前不会影响 也就是多线程编程

JS中的异步操作 ~

js没有多线程概念 但是通过函数回调机制依然可以做到单线程的 并发

比如 js 中的 fetchfetch可以同时访问多个资源

调用 fetch 的时候 程序不会等待 而是会继续执行下去 获取到网络资源的时候才会调用回调函数 主程序和回调函数其实还是在同一个线程上

这就是 JS 实现单线程的并发

什么操作时和异步编程呢?

进行网络编程的时候经常会执行网络请求 数据库访问和文件系统读取 这时候就很适合使用异步编程 多线程的话会浪费I/O资源

异步编程有什么?

image.png

为什么要用promise ?

1.指定回调函数的方式更加灵活

image.png

2.支持连续调用 避免回调地狱👇

image.png

promise 链式调用,

用来解决回调地狱问题,但是只是简单的改变格式,并没有彻底解决上面的问题真正要解决上述问题,一定要利用promise再加上await和async关键字实现异步传同步

终极解决方法

promise + async / await

promise初体验

使用promise封装基于定时器的异步

> Date.now() //获取当前的一个时间戳
<script >
  function doDelay(time) {
    // 1. 创建 promise 对象(pending 状态), 指定执行器函数
    return new Promise((resolve, reject) => {
      // 2. 在执行器函数中启动异步任务
      console.log('启动异步任务')
      setTimeout(() => {
        console.log('延迟任务开始执行...')
        const time = Date.now() // 假设: 时间为奇数代表成功, 为偶数代表失败
        if (time % 2 === 1) { // 成功了
          // 3. 1. 如果成功了, 调用 resolve()并传入成功的 value
          resolve('成功的数据 ' + time)
        } else { // 失败了
          // 3.2. 如果失败了, 调用 reject()并传入失败的 reason
          reject('失败的数据 ' + time)
        }
      }, time)
    })
  }
const promise = doDelay(2000)
promise.then(// promise 指定成功或失败的回调函数来获取成功的 vlaue 或失败的 reason
    value => {// 成功的回调函数 onResolved, 得到成功的 vlaue
      console.log('成功的 value: ', value)
    },
    reason => { // 失败的回调函数 onRejected, 得到失败的 reason
      console.log('失败的 reason: ', reason)
    },
  ) 
  </script>
2.  使用promise封装AJAX请求
    <script >
      /*
      可复用的发 ajax 请求的函数: xhr + promise
      */
      function promiseAjax(url) {
        return new Promise((resolve, reject) => {
          const xhr = new XMLHttpRequest()
          xhr.onreadystatechange = () => {
            if (xhr.readyState !== 4) return
            const {
              status,
              response
            } = xhr
            // 请求成功, 调用 resolve(value)
            if (status >= 200 && status < 300) {
              resolve(JSON.parse(response))
            } else { // 请求失败, 调用 reject(reason)
              reject(new Error('请求失败: status: ' + status))
            }
          }
          xhr.open("GET", url)
          xhr.send()
        })
      }
    promiseAjax('https://api.apiopen.top2/getJoke?page=1&count=2&type=vid
        eo ')
        .then(
          data => {
            console.log('显示成功数据', data)
          },
          error => {
            alert(error.message)
          }
        ) </script>

Promise实操 -- fs模块

回调函数形式 image.png

fs.readFile( () => {
 
})

Promise形式

let p = new Promise ((resolve, reject) => {
 fs.readFile('', (err, data) => {
     if(err)	reject(err);
     resolve(data);
 })
});

p.then((value) => {
 console.log(value.toString());
}, (reason) => {
 console.log(reason);
})

Promise实操 -- AJAX模块

<template>
    <button @click = "add">Promise 封装 AJAX</button>
</template>
​
<script>
import { ref, reactive } from 'vue'
export default {
setup(){
 const add = new Promise((resolve, reject) => {
     const xhr = new xmlHttpRequest();
     xhr.open('GET', 'http://127.0.0.1:8000/serve')
     xhr.send();
     xhr.onreadystatechange() {
       if(xhr.onreadystate == 4){
           if(xhr.state >=200 && xhr.state < 300) {
               resolve(xhr.response);
           }else{
               reject(xhr.status);
           }
       }
     }
 });
 
 add.then(value => {
     consolo.log(value);
 }, reason => {
     console.log(reason);
 });    
     return { add };
 }
}
</script>

Promise封装 -- fs模块

image.png

util.promisify(original)

传入一个遵循常见错误优先的回调风格的函数 以 (err, value) => ...回调作为最后一个参数 并返回一个peomise的版本

其实就是可以直接变成promise的封装方式 不用手动去封装

image.png

Promise封装联系 -- AJAX模块

封装一个函数 sendAJAX 发送 GET AJAX 请求
参数 URL
返回结果 Promise对象
const sendAJAX(url) {
    return new Promise((resolve, reject) => {
        const xhr = new XmlHttpRequset();
        xhr.responseType = 'json';
        xhr.open('GET', url);
        xhr.send();
        xhr.onreadystatechange = function{
            if(xhr.readystate === 4) {
                if(xhr.state >= 200 && xhr.state < 300) {
                    resolve(xhr.response);
                }else{
                    reject(xhr.status);
                }
            }
        }
};
​
sendAJAX('http://127.0.0.1/serve')
.then(value => {
        console.log(value);
}, reason => {
        console.log(reason);
})               

Promise的状态改变

关于Promise的状态

实例对象中的一个属性 【PromiseState

  • pedding 未决定的
  • resolved / fullfilled 成功
  • rejected 失败

对象的值

实例对象中的一个属性 【promiseResult

保存着异步任务成功或者失败的结果

resolve

reject

Promise的基本流程

image.png

如何使用Promise

Ⅰ- Promise 构造函数: Promise (excutor) {}

(1) executor 函数: 执行器 (resolve, reject) => {}

(2) resolve 函数: 内部定义成功时我们调用的函数 value => {}

(3) reject 函数: 内部定义失败时我们调用的函数 reason => {}

说明: executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行,换话说Promise支持同步也支持异步操作

Ⅱ-Promise.prototype.then 方法: (onResolved, onRejected) => {}

(1) onResolved 函数: 成功的回调函数 (value) => {}

(2) onRejected 函数: 失败的回调函数 (reason) => {}

说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调 返回一个新的 promise 对象

Ⅲ-Promise.prototype.catch 方法: (onRejected) => {}

(1) onRejected 函数: 失败的回调函数 (reason) => {}

说明: then()的语法糖, 相当于: then(undefined, onRejected)

(2) 异常穿透使用:当运行到最后,没被处理的所有异常错误都会进入这个方法的回调函数中

Ⅳ-Promise.resolve 方法: (value) => {}

(1) value: 成功的数据或 promise 对象

说明: 返回一个成功/失败的 promise 对象,直接改变promise状态

let p3 = Promise.reject(new Promise((resolve, reject) => {  resolve('OK'); }));      
console.log(p3);

Ⅴ-Promise.reject 方法: (reason) => {}

(1) reason: 失败的原因

说明: 返回一个失败的 promise 对象,直接改变promise状态,代码示例同上

Ⅵ-Promise.all 方法: (promises) => {}

promises: 包含 n 个 promise 的数组

说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一 个失败了就直接失败

let p1 = new Promise((resolve, reject) => { resolve('成功');  })
 let p2 = Promise.reject('错误错误错误');
 let p3 = Promise.resolve('也是成功')
 const result = Promise.all([p1, p2, p3]);
console.log(result);

Ⅶ-Promise.race 方法: (promises) => {}

(1) promises: 包含 n 个 promise 的数组

说明: 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态,

如p1延时,开启了异步,内部正常是同步进行,所以p2>p3>p1,结果是P2

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('OK');
  }, 1000);
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');
//调用
const result = Promise.race([p1, p2, p3]);
console.log(result);

Promise的几个关键问题

如何改变promise对象的状态

  • resolve函数

  • 可以把 pending => fulfilled(resolve)

  • reject函数

    • 可以把pending => rejected
  • 抛出错误

    • throw('出错啦');   //pending => rejected
      

promise对象指定多个回调

promise对象指定多个回调 成功的化 就都会执行

状态没有改变的话 就还是不会执行

let p = new Promise(()) 

改变promise状态和指定函数的回调谁先谁后

image.png

let p = new Promise((resolve, reject) => {
    resolve('OK');
})
​
let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('OK');
    }, 1000)
})
​
p.then(value => {
    resolve(value);
}, reason => {
    reject(reason);
})

执行同步任务的时候 直接调用resolve 这就是先执行resolve

异步任务的时候 等待一段时间 类似定时器 这个时候就是限制性then方法中

一般都是异步任务居多

先指定回调 再去改变状态 回调的执行时机是在调用resolve之后

Promise.then返回的

Promise如何串联多个操作任务

image.png

let p = new Promise((resolve, reject) => {
    resolve("OK");
});
​
p.then( value => {
    resolve("success");
}).then(value => {
    resolve(value); //success
}).then(value => {
    resolve(value); //undefined
})

then方法返回的是上一个函数的返回值 而倒数第二个回调的时候返回的已经是一个成功的promise对象了 而且函数里面没有写return的值 所以最后一个输出的就是undefined

异常穿透

image.png

let p = new Promise((resolve, reject) => {
    reject("Rrr");
});
​
p.then( value => {
    resolve("success");
}).then(value => {
    resolve(value); //success
}).then(value => {
    resolve(value); //undefined
}).catch(reason => {
    console.warn(reason);
})

使用catch的话就只要传一个参数 但是使用then的话就要传递两个参数

失败的话是由最后一个回调来进行处理的

什么是pendingpromise对象 ?

return new Promise(() => {})

如何中断promise链

let p = new Promise((resolve, reject) => {
    reject("Rrr");
});
​
p.then( value => {
    console.log(111);
    return new Promise(() => {})
}).then(value => {
    resolve(value); //success
}).then(value => {
    resolve(value); //undefined
}).catch(reason => {
    console.warn(reason);
})

状态没有改变就不能执行后面的回调函数 所以这个时候就只会输出 111

手写Promise

基本架构搭建

  • index.html
<head>
 <script src = './promise.js'> </script>
......
</head>
​
​
let p = new Promise((resolve, reject) => {
 resolve("OKK");
});
​
p.then(value=>{
 console.log(value);
}, reason => {
 console.warn(reason);
})
  • promise.js
function Promise(executor) {
 //resolve 函数
 function resolve(data) {
     
 }
 //reject函数
 function reject(data) {
     
 }
 
 
 //同步调用【执行器函数】
 executor(resolve, reject)
}
​
//添加then方法
Promise.prototype.then = function(onResolved, onRejected){
 
}

resolve和reject的结构搭建

  • index.html
......
let p = new Promise((resolve, reject) => {
 resolve("OKK");
 reject("Errrrr~");
});
  • promise.js
function Promise(executor) {
 //添加属性
 this.PromiseState = 'pending';
 this.PromiseResult = null;
 //保存实力对象 this 的值
 const self = this; //self _this that 
 //resolve 函数
 function resolve(data) {
     self.PromiseState = 'resolved';    //  fulfilled
     self.PromiseResult = data;
 }
 //reject函数
 function reject(data) {
     self.PromiseState = 'rejected';    //  
     self.PromiseResult = data;
 }
 
 
 //同步调用【执行器函数】
 executor(resolve, reject)
}
​
//添加then方法
Promise.prototype.then = function(onResolved, onRejected){
 
}

抛出异常

  • index.html
......
let p = new Promise((resolve, reject) => {
 throw "error";
});
  • promise.js
function Promise(executor) {
 //添加属性
 this.PromiseState = 'pending';
 this.PromiseResult = null;
 
 //保存实力对象 this 的值
 const self = this; //self _this that 
 
 //resolve 函数
 function resolve(data) {
     self.PromiseState = 'resolved';    //  fulfilled
     self.PromiseResult = data;
 }
 
 //reject函数
 function reject(data) {
     self.PromiseState = 'rejected';    //  
     self.PromiseResult = data;
 }
 
 
 try{
     //同步调用【执行器函数】
    executor(resolve, reject)
 }catch(e) {
     //修改Primose对象状态为 失败
     reject(e);
 }
}
​
//添加then方法
Promise.prototype.then = function(onResolved, onRejected){
 
}

关于同时写了 resolvereject

就象是这样👇

1646448817018

这样的话就会返回reject函数的回调 即改变状态两次

解决方案:

function resolve(data) {
 if( self.promiseSta != 'pending' ){
     self.PromiseState = 'resolved';    //  fulfilled
     self.PromiseResult = data;
 }
}
​
//reject函数
 function reject(data) {
     if( self.promiseSta != 'pending' ){
        self.PromiseState = 'rejected'; //  
        self.PromiseResult = data;
    }
 }
加上一个判断方法的话 就会只执行一次改变状态的方法了

关于 then 方法

  • 如何在then方法中获取到promiseState

直接在then方法中使用this.PromiseState就好了 因为这个其实就是调用了前面那个实例化对象 p 里面的那个 this

Promise.prototype.then=function(onResolved,onRejected){
   //调用回调函数 PromiseState
   if(this.PromiseState == 'fulfilleded') {
       onResolved(this.PromiseResult);
   }
   if(this.PromiseState == 'rejected') {
       onRejected(this.PromiseResult);
   }
}

异步任务

index.js

const p = new Promise((resolve, reject) => {
 setTimeout(() => {
     reject("error");
 }, 1000)
})

因为这里有一个定时器的话 状态就不会立即改变 也就不能及时的调用then方法

解决方案

function Promise(excutor){
 ......
 const callback = {};
 function resolve(data) {
     ....
     if(self.callback.onResolved) {
         self.callback.onResolved(data);
     }
 }
 
 function reject(data) {
     ....
     if(self.callback.onRejected) {
         self.callback.onRejected(data);
     }
 }
}

Promise.prototype.then=function(onResolved,onRejected){
 .......
 //增加一个状态判断 如果是pending的话就调用
 if(this.PromiseState == 'pending') {
     //保存回调函数
 	this.callback = {
         onResolved,	//这个是简写形式 其实就是
         onRejected	//onResolved = onResolved
     }
 }
}

指定多个回调

  • 例👇
let p = new Promise((resolve, reject) => {
   resolve("OKK");
});

p.then(value=>{
   console.log(value);
}, reason => {
   console.warn(reason);
});

p.then(value=>{
   alert(value);
}, reason => {
   alert(reason);
})
  • 之前方法的问题

1646450418082

image.png 这样子保存回调的话 在指定多个回调的时候 后面的回调就会把前面的回调覆盖掉 ~

  • 如果用push保存的话👇 image.png callbacks就会以数组的形式保存两个回调 注:回调是以对象的形式被保存起来的

image.png

  • 所以这样的话在使用成功或者失败的时候就要有一个数组遍历
function Promise(excutor){
 ......
 const callback = {};
 function resolve(data) {
     ....
     self.callbacks.forEach(item => {
         item.onResolved(data);
     });
 }
 
 function reject(data) {
     ....
     self.callbacks.forEach(item => {
         item.onRejected(data);
     })
 }
}

Promise.prototype.then=function(onResolved,onRejected){
 .......
 //增加一个状态判断 如果是pending的话就调用
 if(this.PromiseState == 'pending') {
     //保存回调函数
 	this.callback.push = {
         onResolved,	//这个是简写形式 其实就是
         onRejected	//onResolved = onResolved
     }
 }
}

同步任务 then 返回结果

  • then方法的返回结果是由他执行的回调函数的结果决定的
  • 如果then方法执行的回调中返回的是非promise对象 如数字字符串,那返回也是成功
  • Tip

image.png

  • 实现👇

const p = new Promise((resolve, reject) => {
   resolve('okk');
})

const res = p.then(value => {
   //console.log(521)   //这个返回结果是undefined    
   //return "hello";	//这个返回的结果值就是hello
   
   return new Promise((resolve,reject) =>{
       resolve("success");	//这个就会调用成功的方法        
       reject("error");	//这个就会调用失败的方法        
       throw "FALL";		//这个也会调用失败的方法
   })
   
}, reason => {
   console.warn(reason;)
})
Promise.prototype.then=function(onResolved,onRejected){
   return new Promise((resolve,reject)=> {
       //调用回调函数
       if(this.PromiseState == 'fulfilled') {
         try {
           //获得回调函数的执行结果
           let result = onResolve(this.PromiseResult);
           //判断
           if(result instanceof Promise){
               result.then(value=>{
                   resolve(value);
               }, reason=>{
                reject(reason);    
               })
           }else{
               //结果的对象状态就是成功
               resolve(result);
           }
         }catch{
             reject(e);
         }
   }
  })
}

异步任务then返回结果

Promise.prototype.then=function(onResolved,onRejected){
 const self = this;
 .......
 //增加一个状态判断 如果是pending的话就调用
 if(this.PromiseState == 'pending') {
     //保存回调函数
 	this.callback.push = {
         onResolved: function(){
             //执行成功的回调
             let result= onResolved(self.PromiseResult);
             //判断
             if(result instanceof Promise){
             	result.then(value=>{
            	   		resolve(value);
             	}, reason=>{
             		reject(reason);    
             	})
         	}else{
             	//结果的对象状态就是成功
             	resolve(result);
         	}
         }
         onRejected	//onResolved = onResolved
     }
 }
}

不太懂的顺序

  • 首先判断实例化对象的状态 如果是失败则执行 此时的状态为pending

image.png

然后就会执行 then 方法中的onRejectd

image.png

  • 由于有一个定时器 所以现在的状态是pending 所以执行这个👇

\

image.png

  • 由于 onRejected中没有改变实例化对象的状态 也就是使用

reject() 或者 resolve()

所以实例化对象的状态就还是 pending

下面为解决方案👇

异步修改then结果返回

image.png

image.png

完美版的 then

\

image.png

image.png

Catch 方法与异常穿透

\

image.png

image.png

Promise.resolve 封装

const p = Promise.resolve('OK');
const p2=Promise.resolve(new Promise((resolve,reject)=>{
 resolve('success');
}))

image.png

Promise.reject 封装

const p = Promise.reject('OK');
const p2=Promise.reject(new Promise((resolve,reject)=>{
 resolve('success');
}))

rmise.all封装

let p1 = new Promise((resolve,reject) => {
 resolve("sucess");
})
let p2 = Promise.resolve('okkk');
let p3 = Promise.resolve('Oh no');

let result = Promise.all([p1, p2, p3]);
promise.all = function(promises) {
 return new Promise((resolve, reject) => {
     let count = 0;
     let add = [];
     for(let i = 0; i < promises.lenght;i++) {
         promises[i].then(value => {
             count++;
             arr[i] = value;
             if(count == promises.lenght){
                 resolve(arr);
             }
         }, reason=> {
             reject(reason);
         })
     }
 })
}

Promise.race 封装

回调函数的异步执行

then指定的回调函数是异步执行的 需要等到同步代码执行完毕之后再执行

所以下面函数👇的输出结果是 111 333 222

let p1 = new Promise((resolve, reject) => {
 resolve("seccess");
 console.log(111);
});
p1.then(value=> {
 console.log(222);
});
console.log(333)
所以在之前的代码中需要改进的地方是👇
//------------第一个地方
Promise.prototype.then=function(onResolved,onRejected){
 const self = this;
 .......
 return new Promise((resolve, reject) => {
     //封装函数
     function callback(type){}
     //调用回调函数 PromiseState
     if(self.PromiseState == 'fulfilled'){
         //也就是在这里改为异步的
         setTimeout(() => {
             callback(onResolved);
         });
     }
     if(self.PromiseState == 'rejected'){
         //也就是在这里改为异步的
         setTimeout(() => {
             callback(onRejected);
         });
     }
 })
}

第二个地方

就是那个 function Promise(executor) 那里

let p1 = new Promise((resolve,reject) => {
 resolve("sucess");
})
let p2 = Promise.resolve('okkk');
let p3 = Promise.resolve('Oh no');

let result = Promise.race([p1, p2, p3]);

image.png

image.png

Class版本封装

class Promise {
 //构造方法
	constructor(executor){}
 // then方法封装
 then(onResolved, onRejected){};
 //catch
 catch(onRejected){};
 //resolve
 static resolve(value){};
 //reject
 static reject(value){};
 //all
 static all(value){};
 //race
 static race(value){};
}

function Promise(executor) 函数里的东西放在这里

resolve reject all race方法前要加一个static是因为要表明他是一个类而不是一个实例化对象

async与await

  • 只能说为了一个东西学了全部 我就是一个活生生的例子 为了学到这个 asyncawait 硬生生看了全部的这个 不过所幸要看完了 不过后面还是要好多东西md 算了 学!!!!!!

async函数

返回的是一个 promise 对象

promise对象的返回值是由async的返回值决定的

async function main() {
	//如果返回值不是一个promise对象的数据
 return 521;
 //如果是一个promise的对象
 return new Promise((resolve, reject) => {
     resolve("nice");
     reject("oh no");
 })
 throw 'oh my god~'
}
let result = main();
console.log(result);

await表达式

  • await右侧的表达式一般是一个promise对象 但是也可以是其他的值
  • 如果表达式是 promise 对象的话 await返回的就是promise 成功的值
  • 如果表达式是其他的值 直接将此值作为 await 的返回值就好了
  • await 必须写在 async 函数中, 但是 async 函数中可以没有 await
  • 如果await的promise失败了 就会抛出异常 就需要try...catch捕获处理
async function main() {
 let p = Promise((resolve,reject)=> {
     resolve("okk");
     reject("error");
 })
 //右侧为promise的情况
 let res = await p;
 右//侧为其他数据类型的数据
 let res2 = await 20;
 //如果是promise是失败的状态
 try{
     let res3 = await p;
 }catch {
     console.log(e);
 }
}

async和await的结合

小案例 获取三个文件中的内容 再做内容的拼接

  • 老版本

image.png

  • ⭐新版本

image.png

async function main() {
   try{
       let data1 = await mineReadFile('./1x.html');
       let data2 = await mineReadFile('./2x.html');
       let data3 = await mineReadFile('./3x.html');
       console.log(data1 + data2 + data3);
   }catch(e) {
       console.log(e.code);
   }
}
main();

async 和 await结合发送AJAX

<template>
	<button @click = "GetInfo">点击获取信息</button>
</template>

<script>
import {ref, reactive} from 'vue';
export default {
setup() {
 function sendAJAX(url) {
 	return new Promise((resolve, reject) => {
     	const xhr = new XmlHttpRequset();
     	xhr.responseType = 'json';
     	xhr.open('GET', url);
     	xhr.send();
     	xhr.onreadystatechange = function{
         	if(xhr.readystate === 4) {
             	if(xhr.state >= 200 && xhr.state < 300) {
                 	resolve(xhr.response);
             	}else{
                 	reject(xhr.status);
             	}
         	}
     	}
		}
 };
 //------------正文---------------                       
 async function GetInfo() {
     let Info = await sendAJAX('http://128.0.0.1:8000');  
     console.log(Info);
 }                       
}                                                
}
</script>

为什么还是觉得好麻烦呢 ????

其实主要还是这一段麻烦 其实这个不必担忧 等学完axios就好了 到时候好像可以直接干嘛干嘛的就发送AJAX请求 哎 对应了上文的一句话

image.png

Md 学!!!!!!

\