如何从XMLHttpRequest创建自定义获取API

What is your worst nightmare?

你最可怕的噩梦是什么?

That sounded dark, but it’s not a rhetorical question. I really want to know because I am about to tell you mine. Along the way, we will learn some things like how the fetch API works and also how function constructors work.

听起来很黑,但这不是一个反问。 我真的很想知道,因为我要告诉你我的。 在此过程中,我们将学习一些知识,例如获取API的工作方式以及函数构造函数的工作方式。

Sorry I digress, back to my worst nightmare. If you had asked me that question last week it would be the below list in no particular order:

对不起,我离题了,回到我最糟糕的噩梦。 如果您上周曾问过我这个问题,则该列表按以下顺序排列:

  • Writing Pre-ES6 syntax

    编写ES6之前的语法
  • No fetch API

    没有提取API
  • No Transpiler (Babel/Typescript)

    无转换器(Babel /打字稿)
  • Uncle Bob said that I’m a disappointment (Kidding)

    鲍伯叔叔说我很失望(开玩笑)

If your list matches mine then I have to say that you are a very weird person. As luck would have it I was called to work on a project that brought to life my nightmare list (excluding the last one). I was to add a new feature to the application. It was a legacy codebase that used purely pre-es6 syntax and XMLHttpRequest (the horror) for its AJAX requests.

如果您的名单与我的名单相符,那么我不得不说您是一个非常奇怪的人。 幸运的是,我被要求从事一个使我的噩梦清单(不包括最后一个清单)栩栩如生的项目。 我当时要向应用程序添加新功能。 它是一个遗留代码库,仅对其AJAX请求使用纯es6之前的语法和XMLHttpRequest(恐怖)。

So in a bid to make the experience palatable, I decided to create a function that abstracts all the AJAX requests I would be making and expose APIs that mimics the new fetch API (well not really). This is also after I watched the Javascript: The new hard parts video on frontend masters where an amazing explanation of how the fetch API works under the hood was given. Let’s begin.

因此,为了使体验变得可口,我决定创建一个函数,该函数抽象我将要发出的所有AJAX请求,并公开模仿新的访存API的API (并非如此)。 这也是在我观看了Javascript:前端大师上的新硬部分视频之后,其中对fetch API的工作原理进行了令人惊讶的解释。 让我们开始。

First, I had to look up how XMLHttpRequest works. Then I started writing the function. My first iteration looked like this:

首先,我必须查看XMLHttpRequest的工作方式。 然后,我开始编写函数。 我的第一次迭代看起来像这样:

"use strict";function fetch() {var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};var xhr = new XMLHttpRequest();var onFufillment = [];var onError = [];var onCompletion = [];var method = "GET" || options.method;xhr.onreadystatechange = function () {var _data = this;if (this.readyState == 4 && this.status == 200) {// Action to be performed when the document is read;onFufillment.forEach(function (callback) {callback(_data);});onCompletion.forEach(function (callback) {callback(_data);});} else if (this.readyState == 4 && this.status !== 200) {onError.forEach(function (callback) {callback(_data);});onCompletion.forEach(function (callback) {callback(_data);});}};xhr.open(method, url, true);xhr.send();return {then: function then(fufillmentFunction) {onFufillment.push(fufillmentFunction);},catch: function _catch(errorFunction) {onError.push(errorFunction);},finally: function _finally(completionFunction) {onCompletion.push(completionFunction);}};
}

Let me work through what the function does:

让我来研究一下函数的作用:

  • We are checking if the url argument is passed into the function. Defaulting to an empty string if nothing is passed

    我们正在检查url参数是否传递给函数。 如果未传递任何内容,则默认为空字符串

  • We are also doing the same thing for the options argument. Defaulting to an empty object if nothing is passed

    我们对options参数也做同样的事情。 如果未传递任何内容,则默认为空对象

  • Then we create a new instance of the XMLHttpRequest

    然后我们创建一个XMLHttpRequest的新实例
  • We create 4 variables onFufillment, onError, onCompletion and method

    我们创建4个变量onFufillment, onError, onCompletion and method

  • onFufillment is an array that stores all the functions passed into the then method

    onFufillment是一个数组,用于存储传递给then方法的所有函数

  • onError is an array that stores all the functions passed into the catch method

    onError是一个数组,用于存储传递给catch方法的所有函数

  • onCompletion is an array that stores all the functions passed into the finally method

    onCompletion是一个数组,用于存储传递给finally方法的所有函数

  • method is used to store the HTTP method that will be used, it defaults to GET

    method用于存储将要使用的HTTP方法,默认为GET

  • We then pass a function into the onreadystatechange method of xhr which will be called when the state of the request changes

    然后,我们将一个函数传递到xhronreadystatechange方法中,该方法将在请求状态更改时被调用

  • In the function, we save this into a _data variable so that it can be passed into the forEach functions without losing its context (I know this is annoying)

    在功能方面,我们保存this_data变量,以便它可以传递到在foreach功能没有失去它的上下文(我知道this很烦人)

  • We then check if the request is completed (readyState == 4 ) and if the request is successful, then we loop through onFufillment and onCompletion arrays, calling each function and passing _data into it

    然后,我们检查,如果该请求已完成( readyState == 4 )如果请求是成功的,那么我们循环onFufillment and onCompletion数组,调用每个函数并传递_data进去

  • If the request fails we do the same thing with the onCompletion and onError arrays

    如果请求失败,我们将使用onCompletion and onError数组执行相同的操作

  • Then we send off the request with the passed in parameters

    然后,我们使用传入的参数发送请求
  • After that, we return an object containing three functions, then. catch and finally which have the same names as the fetch API.

    之后,我们返回一个包含三个函数的对象。 catch and finally与fetch API具有相同的名称。

  • catch pushes the function that is passed as an argument into the onError array

    catch将作为参数传递的函数推入onError数组

  • then does the same thing with the onFufillment array

    thenonFufillment数组做同样的事情

  • finally does the same with the onCompletion array

    finallyonCompletion数组做同样的onCompletion

The usage of this API will look like this:

该API的用法如下所示:

var futureData = fetch('https://jsonplaceholder.typicode.com/todos/2');
futureData.then(function(data){console.log(data)
})futureData.finally(function(response){console.log(response);
});futureData.catch(function(error){console.log(error);
})

It works!!! But not nearly as the real fetch implementation. Can we do better than this? Of course, we can. We can still add more features to the function. We could make it chainable, that is, we can give it the ability to chain methods together.

有用!!! 但还不及真正的获取实现。 我们可以做得更好吗? 当然,我们可以。 我们仍然可以向该功能添加更多功能。 我们可以使其可链接,也就是说,我们可以使它将方法链接在一起。

On the second iteration, this is how it looks:

在第二次迭代中,它是这样的:

"use strict";function fetch() {var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var xhr = new XMLHttpRequest();var onFufillment = [];var onError = [];var onCompletion = [];var method = "GET" || options.method;xhr.onreadystatechange = function () {var _data = this;if (this.readyState == 4 && this.status == 200) {// Action to be performed when the document is read;onFufillment.forEach(function (callback) {callback(_data);});onCompletion.forEach(function (callback) {callback(_data);});} else if (this.readyState == 4 && this.status !== 200) {onError.forEach(function (callback) {callback(_data);});onCompletion.forEach(function (callback) {callback(_data);});}};xhr.open(method, url, true);xhr.send();return {then: function then(fufillmentFunction) {onFufillment.push(fufillmentFunction);return this;},catch: function _catch(errorFunction) {onError.push(errorFunction);return this;},finally: function _finally(completionFunction) {onCompletion.push(completionFunction);return this;}};
}

The usage of the API will look like this:

API的用法如下所示:

var futureData = fetch('https://jsonplaceholder.typicode.com/todos/2');futureData.then(function(data){console.log(data)
}).then(function(response){console.log(response);
}).catch(function(error){console.log(error);
});

What did it do? The only difference in the second iteration was in the then, catch and finally where I just returned this which means each function returns itself basically enabling it to be chained (partially).

它做了什么? 在第二迭代中的唯一区别是在then, catch and finally ,我刚回到this意味着每个函数返回本身基本上使它能够被链接(部分地)。

Better right? But can we do better than this? Of course, we can. The returned object can be put in the function's prototype so that we can save memory in a situation where the function is used multiple times.

更好吧? 但是我们能做得更好吗? 当然,我们可以。 可以将返回的对象放在函数的原型中,以便在多次使用函数的情况下节省内存。

This is how it looks on the third iteration:

这是在第三次迭代中的样子:

"use strict";
function fetch() {var fetchMethod = Object.create(fetch.prototype);var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var xhr = new XMLHttpRequest();fetchMethod.onFufillment = [];fetchMethod.onError = [];fetchMethod.onCompletion = [];var method = "GET" || options.method;xhr.onreadystatechange = function () {var _data = this;if (this.readyState == 4 && this.status == 200) {// Action to be performed when the document is read;fetchMethod.onFufillment.forEach(function (callback) {callback(_data);});fetchMethod.onCompletion.forEach(function (callback) {callback(_data);});} else if (this.readyState == 4 && this.status !== 200) {fetchMethod.onError.forEach(function (callback) {callback(_data);});fetchMethod.onCompletion.forEach(function (callback) {callback(_data);});}};xhr.open(method, url, true);xhr.send();return fetchMethod;
};
fetch.prototype.then = function(fufillmentFunction) {this.onFufillment.push(fufillmentFunction);return this;
};
fetch.prototype.catch = function(errorFunction) {this.onError.push(errorFunction);return this;
};
fetch.prototype.finally = function(completionFunction) {this.onCompletion.push(completionFunction);return this;
};

So this version basically moves the returned function into the fetch’s prototype. If you don’t understand the statement then I recommend checking out this article about Javascript’s prototype (Thanks, Tyler McGinnis).

因此,此版本基本上将返回的函数移至提取的原型中。 如果您不理解该声明,那么我建议您阅读有关Javascript原型的本文(谢谢,Tyler McGinnis)。

Is this an improvement? Yes!!! Can we do better? Of course, we can. We can use the new keyword to our advantage here and remove the explicit return statement.

这有改善吗? 是!!! 我们可以做得更好吗? 当然,我们可以。 我们可以在这里使用new关键字来发挥优势,并删除显式的return语句。

The next iteration will look like this:

下一次迭代将如下所示:

"use strict";
function Fetch() {var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};var xhr = new XMLHttpRequest();this.onFufillment = [];this.onError = [];this.onCompletion = [];var method = "GET" || options.method;var internalFetchContext = this;xhr.onreadystatechange = function () {var _data = this;if (this.readyState == 4 && this.status == 200) {// Action to be performed when the document is read;internalFetchContext.onFufillment.forEach(function (callback) {callback(_data);});internalFetchContext.onCompletion.forEach(function (callback) {callback(_data);});} else if (this.readyState == 4 && this.status !== 200) {internalFetchContext.onError.forEach(function (callback) {callback(_data);});internalFetchContext.onCompletion.forEach(function (callback) {callback(_data);});}};xhr.open(method, url, true);xhr.send();
};
Fetch.prototype.then = function(fufillmentFunction) {this.onFufillment.push(fufillmentFunction);return this;
};
Fetch.prototype.catch = function(errorFunction) {this.onError.push(errorFunction);return this;
};
Fetch.prototype.finally = function(completionFunction) {this.onCompletion.push(completionFunction);return this;
};

Let me explain the changes:

让我解释一下这些变化:

  • Changed the name of the function from fetch to Fetch, it’s just a convention when using the new keyword

    将函数的名称从fetch更改为Fetch,这只是使用new关键字时的约定

  • Since I am using the new keyword I can then save the various arrays created to the this context.

    由于我使用的是new关键字,因此可以将创建的各种数组保存this上下文中。

  • Because the function passed into onreadystatechange has its own context I had to save the original this into its own variable to enable me to call it in the function (I know, this can be annoying)

    由于传递给函数onreadystatechange都有自己的内容,我不得不原来保存this到它自己的变量,使我能够调用它的功能(我知道, this可能是讨厌)

  • Converted the prototype functions to the new function name.

    将原型函数转换为新的函数名称。

The usage will look like this:

用法如下所示:

var futureData = new Fetch('https://jsonplaceholder.typicode.com/todos/1');
futureData.then(function(data){console.log(data)
}).then(function(response){console.log(response);
}).catch(function(error){console.log(error);
})

Voilà! That was really fun. But can we do better? Of course, we can.

瞧! 那真的很有趣。 但是,我们可以做得更好吗? 当然,我们可以。

But I will leave that to you. I would love to see your own implementation of the API in the comments below.

但我会留给你。 我希望在下面的评论中看到您自己的API实现。

If you liked the article (and even if you didn’t), I would appreciate a clap (or 50) from you. Thank you.

如果您喜欢这篇文章(即使您不喜欢),也希望得到您的鼓掌(或50)。 谢谢。

翻译自: https://www.freecodecamp.org/news/create-a-custom-fetch-api-from-xmlhttprequest-2cad1b84f07c/

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

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

相关文章

leetcode637. 二叉树的层平均值

给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。示例 1:输入:3/ \9 20/ \15 7 输出:[3, 14.5, 11] 解释: 第 0 层的平均值是 3 , 第1层是 14.5 , 第2层是 11 。因此返回 [3, 14.5, 11] 。/*** Definition for a b…

5.3 上午

观看英语课程——《恋练有词》 学习Linux 转载于:https://www.cnblogs.com/bgd140206110/p/6801164.html

AD库转换为KiCAD库的方法

AD库转换为KiCAD库的方法 参照博主另外一篇文档: AD转换为KiCAD的方法,点击此处转载于:https://www.cnblogs.com/zhiqiang_zhang/p/11109560.html

遗传算法求解装箱问题c语言,求解装箱问题的遗传算法-南昌航空大学期刊网.pdf...

求解装箱问题的遗传算法-南昌航空大学期刊网1998 2 Journal of Nanchang Institute of Aeronautical Technology 21998方 平    李 娟( 南昌航空工业学院)  ( 西北工业大学): ( Bin Packing) ,, , D( irst it De-creasing) ,: ; ; ;: TP301. 6( )( Bin Packing) , :1 2 …

mysql索引随记

为什么80%的码农都做不了架构师?>>> 先了解下Btree:https://my.oschina.net/u/3646190/blog/1593094 为什么每个数据项,即索引字段要尽量的小,比如int占4字节,要比bigint8字节少一半? 通过上面…

leetcode79. 单词搜索(回溯算法)

给定一个二维网格和一个单词,找出该单词是否存在于网格中。 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。 示例: board [ [‘A’,‘…

react钩子_迷上了钩子:如何使用React的useReducer()

react钩子So the React Conference just happened and as always something new happened. Hooks happened! The React team talked about suspense, lazy loading, concurrent rendering, and hooks :D.因此,React会议刚刚发生,并且一如既往地发生了一些…

开发注意事项

明确需求 - 沟通 - 定好上下游接口 次序乱不得转载于:https://www.cnblogs.com/zslzz/p/6802437.html

c语言写桌面程序unity,Unity和iOS原生界面交互示例

注意上面的Main方法中出现的UnityAppController,该类就是作为控制类来实现Unity在iOS上显示的功能,在Main方法中就是将该控制器作为参数传递,即Main方法之后就会进入该类执行。所以这是我们进入到UnityAppController.mm,来查看该类…

oracle审计实施

1、语句审计 Audit session; Audit session By ; 与instance连接的每个会话生成一条审计记录。审计记录将在连接时期插入并且在断开连接时期进行更新。 保留有关会话的信息比如连接时期断开连接时期处理的逻辑和物理I/O,以及更多信息将存储在单独一条审计 记录中…

JPDA 架构研究5 - Agent利用环境指针访问VM (内存管理篇)

引入: 我们在前面说到JVMTI的客户端Agent,又提到Agent通过环境指针来访问VM。这里就来看看环境指针到底有多大的访问VM的能力。 分类1:内存管理 a.Allocate. 分配内存 jvmtiError Allocate(jvmtiEnv* env,jlong size,unsigned char** mem_ptr) size:分配…

leetcode94. 二叉树的中序遍历(dfs)

给定一个二叉树,返回它的中序 遍历。示例:输入: [1,null,2,3]1\2/3输出: [1,3,2]代码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val x; }* }*/ class …

vtk删除一个actor_如何构建一个基于actor的简单区块链

vtk删除一个actorScalachain is a blockchain built using the Scala programming language and the actor model (Akka Framework).Scalachain是使用Scala编程语言和参与者模型( Akka Framework )构建的区块链。 In this story I will show the development process to build…

java枚举的简单介绍

1.枚举,enum关键字,相当于public final static. 2.举例: 首先定义了一个名为spiciness的枚举类型。 public enum Spiciness {NOT, MILD, MEDIUM, HOT, FLAMING } 再来测试一下enum,这个测试方法表明它有tostring()方法&#xff0…

浏览器中插入富文本编辑器

常用的富文本编辑器有CKEditor、UEEditor、TinyEditor、KindEditor等、以下以kindeditor编辑器的使用为例。 1.官网下载KindEditor编辑器http://kindeditor.net/down.php, 当前最新版本为4.1.11,解压缩后放入项目的static目录,作为js插件引用…

获取Extjs文本域中的内容

经常在Ext.select()和Ext.query()等问题上纠结,今天终于有了点新认识: 需求,假设我们的页面上有个panel ,其id为clusterstab_edit_details,这个panel的内部有个textarea,这个textarea的name为editDetails_Description,那么我们有多少方法可以…

android触摸指纹会触发按键功能,Android P新特性:利用触摸指纹识别器能阻止手机息屏...

设想你正在阅读手机上的文章,突然间显示屏变暗了一点。显然,你设置的30秒或1分钟超时息屏对于常规使用来说还可以,但对于阅读纯文本片段,还远远不够。因此,这时你会轻触屏幕,可能会上下滑动,以防…

leetcode37. 解数独(hashmap+回溯)

编写一个程序,通过已填充的空格来解决数独问题。 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 空白格用 ‘.’ 表示。 Note: 给定的数独序…

malloc、calloc、realloc和alloca各种的区别

需要先包含头文件 #include"malloc.h"malloc是标准的在堆中开辟新的空间比如char *pt(char *)malloc(10*sizeof(char));需要free(p)才会释放空间calloc也是开辟空间,但是使用方式不一样比如char *pt(char *)calloc(100, sizeof(char));然后用calloc开辟的…

如何对第一个Vue.js组件进行单元测试

by Sarah Dayan通过莎拉达扬 In Build Your First Vue.js Component we made a star rating component. We’ve covered many fundamental concepts to help you create more complex Vue.js components.在“ 构建您的第一个Vue.js组件”中,我们制作了星级评分组件…