JS手写题解析

手写Promise

javascript 复制代码
class MyPromise {
  constructor(executor) { // executor执行器
    this.status = 'pending' // 等待状态
    this.value = null // 成功或失败的参数
    this.fulfilledCallbacks = [] // 成功的函数队列
    this.rejectedCallbacks = [] // 失败的函数队列
    const that = this
    function resolve(value) { // 成功的方法
      if (that.status === 'pending') {
        that.status = 'resolved'
        that.value = value
        that.fulfilledCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法
      }
    }
    function reject(value) { //失败的方法
      if (that.status === 'pending') {
        that.status = 'rejected'
        that.value = value
        that.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了

javascript 复制代码
// 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);
	else
		xhr.send(null);})

首先定义了一个函数ajax,并有四个传值,这边可以看下实例,来了解参数定义

javascript 复制代码
// 定义一个函数,使用 ajax 发送请求
function fetchData() {
  // 请求配置对象,包括 url、type、data、dataType
  const config = {
    url: 'https://jsonplaceholder.typicode.com/posts/1', // 示例 API
    type: 'GET', // 请求方式,GET 或 POST
    data: 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必须是用双引号包裹的

javascript 复制代码
let str = "Hello World";

let lowerCaseStr = str.toLowerCase();

console.log(lowerCaseStr); // 输出: "hello world"
console.log(str); // 输出: "Hello World",原始字符串未被改变
javascript 复制代码
// 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。

相关推荐
活宝小娜1 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点1 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow1 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o1 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
----云烟----2 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024062 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic2 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā2 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
向宇it2 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康2 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud