手写Promise
class MyPromise {constructor(executor) { // executor执行器this.status = 'pending' // 等待状态this.value = null // 成功或失败的参数this.fulfilledCallbacks = [] // 成功的函数队列this.rejectedCallbacks = [] // 失败的函数队列const that = thisfunction resolve(value) { // 成功的方法if (that.status === 'pending') {that.status = 'resolved'that.value = valuethat.fulfilledCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法}}function reject(value) { //失败的方法if (that.status === 'pending') {that.status = 'rejected'that.value = valuethat.rejectedCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法}}try {executor(resolve, reject)} catch (err) {reject(err)}}then(onFulfilled, onRejected) {if (this.status === 'pending') {// 等待状态,添加回调函数到成功的函数队列this.fulfilledCallbacks.push(() => {onFulfilled(this.value)})// 等待状态,添加回调函数到失败的函数队列this.rejectedCallbacks.push(() => {onRejected(this.value)})}if (this.status === 'resolved') { // 支持同步调用console.log('this', this)onFulfilled(this.value)}if (this.status === 'rejected') { // 支持同步调用onRejected(this.value)}}
}// 测试
function fn() {return new MyPromise((resolve, reject) => {setTimeout(() => {if(Math.random() > 0.6) {resolve(1)} else {reject(2)}}, 1000)})
}
fn().then(res => {console.log('res', res) // res 1},err => {console.log('err', err) // err 2})
解析:
首先是初始化了一个Promise实例,并定义了状态、值、成功回调和失败回调,并使用that来指向调用者。
resolve函数用于执行成功回调
reject函数用于执行失败函数
try尝试执行executor函数,并传入resolve和reject,当发生err的时候捕捉err
再用then方法注册Promise成功和失败的回调函数
这边可以看下运行的顺序来更好的理解代码
首先executor(resolve,reject)会try,然后最开始肯定是pending状态,会将回调函数调到列队中。
随后settimeout启动生成random,开始执行resolve or reject
这边是调用了resolve,他会更换状态并且执行列队中的函数
res => {
console.log('res', res) // res 1
},
手写AJAX
拿下Promise后就可以趁热打铁来了解AJAX了
// url:"url路径" type:请求方式 data:请求参数类型 dataType:返回的字符串类型
function ajax({url,type,data,dataType}){
return new Promise(function(resolve,reject){//1. 创建异步请求对象var xhr=getXhr();// 备注:无需通过上面的方式,简单的创建异步请求对象的简化代码如下:// var xhr = window.XMLHttpRequest ? new XMLHttprequest() : new ActiveXObject('Microsoft.XMLHttp');//2.绑定监听事件xhr.onreadystatechange=function(){// 当异步请求状态变为4时,并且返回的状态码为200,接收响应成功if(xhr.readyState==4&&xhr.status==200){// 当返回接收的字符串类型为json串时,自动转换json串if(dataType!==undefined&&dataType.toLowerCase()==="json")var res=JSON.parse(xhr.responseText)else// 否则直接获取返回的响应文本中的内容var res=xhr.responseText// 通过Promise,将返回的数据向后传递,相当于获取到请求数据将数据return出来resolve(res);}}// 如果请求方式为get请求,则将请求参数拼接在url后if(type.toLowerCase()==="get"&&data!==undefined){url+="?"+data;}//3.打开连接xhr.open(type,url,true);// 如果请求方式为post请求,则修改请求消息头if(type.toLowerCase()==="post")//增加:设置请求消息头xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");//4.发送请求if(type.toLowerCase()==="post"&&data!==undefined)xhr.send(data);elsexhr.send(null);})
首先定义了一个函数ajax,并有四个传值,这边可以看下实例,来了解参数定义
// 定义一个函数,使用 ajax 发送请求
function fetchData() {// 请求配置对象,包括 url、type、data、dataTypeconst config = {url: 'https://jsonplaceholder.typicode.com/posts/1', // 示例 APItype: 'GET', // 请求方式,GET 或 POSTdata: null, // 请求参数,对于 GET 请求,参数直接拼接在 URL 后面dataType: 'json' // 返回的数据类型,这里指定为 JSON};// 调用 ajax 函数,并返回 Promise 对象return ajax(config).then(response => {console.log('请求成功:', response);// 这里可以对获取到的数据进行进一步处理或返回return response;}).catch(error => {console.error('请求失败:', error);throw error; // 可以选择抛出异常或者进行其他处理});
}
然后rentun了一个Promise
这里面有很多可能不认识的东西,要逐一了解下
比如toLowerCase,他不会改变原字符串,可以将来的字母都转化为小写字母
JSON.parse可以将字符串转化为javascript对象,但key必须是用双引号包裹的
let str = "Hello World";let lowerCaseStr = str.toLowerCase();console.log(lowerCaseStr); // 输出: "hello world"
console.log(str); // 输出: "Hello World",原始字符串未被改变
// JSON 字符串
const jsonStr = '{"name": "John", "age": 30, "city": "New York"}';// 使用 JSON.parse 解析 JSON 字符串
const jsonObj = JSON.parse(jsonStr);console.log(jsonObj); // 输出: { name: 'John', age: 30, city: 'New York' }
console.log(jsonObj.name); // 输出: "John"
console.log(jsonObj.age); // 输出: 30
这样xhr.onreadystatechange里面的内容就很好理解了,就是当请求成功后将相应内容提取出来作为resolve。