JS手写题解析

news2024/12/23 14:10:59

手写Promise

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了

// 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,并有四个传值,这边可以看下实例,来了解参数定义

// 定义一个函数,使用 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必须是用双引号包裹的

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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1821817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我的创作纪念日 --- 携手CSDN的512天

起航 时间过得可真快啊,转眼间距离我发的第一篇文章已经有512天了,那是一个寒假,当我发现自己又浑浑噩噩的过完了一个学期时,我才开始思考自己想拥有怎样的人生,然后我就写下了自己的第一篇文章 about me,…

哪些国产项目管理软件最受欢迎?详细解读六大主流系统

满足国产化诉求的6款项目管理系统:PingCode、Worktile、Teambition、禅道、华为云DevCloud、Tapd。 国产项目管理软件以其定制化高、适应本土市场的优势,正成为越来越多企业的选择。本文将探讨几款优秀的国产项目管理工具,帮助您找到提升团队…

C# WPF入门学习主线篇(三十三)—— 使用ICommand实现命令绑定

C# WPF入门学习主线篇(三十三)—— 使用ICommand实现命令绑定 在MVVM模式中,命令绑定是将用户交互(如按钮点击)与ViewModel中的方法连接起来的一种机制。使用ICommand接口可以实现这一功能,从而将UI逻辑与业…

癫狂头歌动态规划之跳跃问题Python

第一关跳跃问题 这里我照着图片的代码敲市过不去,真够癫狂的 def CollectValues():n, m map(int, input().split()) #获得输入信息p [list(map(int, input().split())) for i in range(n)] #获得输入信息dp [[-10000] * m for i in range(n)] #初始化动态规划数…

【K8s】专题五(2):Kubernetes 配置之 Secret

以下内容均来自个人笔记并重新梳理,如有错误欢迎指正!如果对您有帮助,烦请点赞、关注、转发!欢迎扫码关注个人公众号! 目录 一、基本介绍 二、主要特性 三、资源清单(示例) 四、常用操作 一…

入职3年-我如何做一名AI产品经理(文末福利)

引言 从2021年校招加入京东开始,我一直从事AI产品经理的工作,有幸见证了AI行业的热情从一台台服务器烧到了全世界各个角落,也见证了京东AI中台团队的影响力如何一步步的扩大。从21年的迷茫到24年的坚定,很庆幸我正走在适合自己的…

深圳职工餐厅安全检测新策略:自动可燃气体报警器的作用

在现代化的都市生活中,安全问题一直备受关注。 对于深圳众多职工餐厅来说,如何确保餐厅内的燃气使用安全,防止因可燃气体泄露而引发的火灾事故,成为了一项重要的挑战。 近年来,自动可燃气体报警器以其高度的灵敏度和…

微软无所不知的人工智能召回功能“Recall”被推迟,将不会与 Copilot Plus PC 一起提供

微软计划下周推出新的 Copilot Plus 个人电脑,取消其备受争议的 Recall 功能,该功能可以截取您在这些新笔记本电脑上所做的所有操作。该软件制造商推迟了 Recall,以便可以通过 Windows Insider 程序对其进行测试,此前该公司最初承…

Redis 7.x 系列【2】单机部署

有道无术,术尚可求,有术无道,止于术。 本系列Redis 版本 7.2.5 源码地址:https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. Windows2. Linux 1. Windows Redis作为一个高性能的内存数据库,和Linu…

爬虫-模拟登陆博客

import requests from bs4 import BeautifulSoupheaders {user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36 } # 登录参数 login_data {log: codetime,pwd: shanbay520,wp-submit: …

C++ 36 之 this指针

#include <iostream> #include <string.h> using namespace std;// this指针 永远指向当前对象 class Students06{ public:int age;// int m_age; //member成员首字母mStudents06(int age){// 1.解决命名冲突的问题 this指针找成员变量需要使用->符号this->…

【Linux】基础指令(一)

一、ls指令 语法&#xff1a; ls [选项][目录或文件] 功能&#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息 常见选项&#xff1a; -a 列出目录下的所有文件&#xff0c;包括以 . 开头的隐含文件。 -d …

32T存储删除视频的恢复方法

由于存储技术的发展和普及目前很多行业都开始使用小型存储&#xff0c;NAS可以通过网络进行数据上传和读取&#xff0c;使用极为方便。但是由于NAS设备容量较大且碎片较多&#xff0c;所以此类设备删除或者格式后恢复难度是比较大的&#xff0c;下边我们来分享下32T存储的恢复方…

不愧是字节,图像算法面试真细致

这本面试宝典是一份专为大四、研三春招和研二暑假实习生准备的珍贵资料。 涵盖了图像算法领域的核心知识和常见面试题&#xff0c;包括卷积神经网络、实例分割算法、目标检测、图像处理等多个方面。不论你是初学者还是有经验的老手&#xff0c;都能从中找到实用的内容。 通过…

网站接口是怎么开发的,开发之后是怎么用的

网站接口的开发流程 1.确定接口需求 在开发接口之前我们先要知道&#xff0c;要开发什么样的接口&#xff0c;这个接口是用来干什么的&#xff0c;得先知道相关的需求&#xff0c;才能规划下一步&#xff0c;比如客户想要一个文章列表&#xff0c;那么我们就知道这个需求…

算法day29

第一题 695. 岛屿的最大面积 本题解法&#xff1a;采用bfs的算法&#xff1b; 本题使用象限数组的遍历方法和定义布尔数组vis来遍历每一个元素的上下左右元素&#xff0c;防治被遍历的元素被二次遍历&#xff1b; 本题具体分析如上题故事&#xff0c;但是由于要求区域的最大面…

爆肝三天,制作属于自己的地图——DAY3(地图数据发布详细教程)

4&#xff0c;重建顶层。 倾斜摄影数据的组织方式&#xff0c;一个 Data 目录下的 Tile 可能会成千上万&#xff0c;如果不使用重建顶层&#xff0c;那么输出的3DTiles的包围盒会非常非常多&#xff0c;增加加载时长。重建顶层&#xff0c;程序会根据瓦片的空间结构关系采用八…

opencv安装笔记 各种平台

目录 python安装opencv-python c 麒麟arm系统安装和用法 python安装opencv-python pypi上搜索 Search results PyPI 现在安装是一个版本&#xff0c;大于3.6都可以安装 c 麒麟arm系统安装和用法 参考&#xff1a; ffmpeg rknn麒麟系统 安装 opencv_ffmpeg4 解码示例-CSDN…

Vitis HLS 学习笔记--Vitis Accelerated Libraries介绍

1. 简介 Vitis Accelerated Libraries&#xff0c;包含很多现成的库&#xff0c;这些库都是开源的&#xff0c;也就是说代码是公开的&#xff0c;而且已经优化过&#xff0c;可以让程序运行得更快。你不需要改变太多你的代码&#xff0c;就能让你的程序速度提升。 这些库有很…

两个螺旋面的交线

已知轴截面齿形&#xff0c;先得到螺旋面 然后在计算出对应的端面齿形 在用端面齿形来计算和另一个螺旋面的相交曲线。 三维验证这个方法可行&#xff01;