如何從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.pswp.cn/news/392973.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/392973.shtml
英文地址,請注明出處:http://en.pswp.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組件”中,我們制作了星級評分組件…