成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇帶給你網絡請求與I/O雜談

網絡 網絡管理
本篇文章談談自己對XHR及相關標準,然后談談操作系統的I/0及Node的異步I/0。希望對你有所幫助!

[[399853]]

前言

我始終覺得博客不是想什么就寫什么的,一定是有某一個契機,使得我們對某一個點或者方向有深度探索繼續學習或者加深印象的過程,并有體系的將這個過程記錄下來,昨天其實就在寫博客了,寫的點是關于XMLHttpRequest的,是因為之前跟一個同學談及到了它,以及相關的網絡請求標準AJAX、Fetch、axios等,最近,因為在等待論文盲審的過程中,有了寫書的想法,于是便匆匆開始了寫書之旅,一本關于Node的原理及實踐應用的書,暫取名《Node雜談》,目前已經寫了61頁了,但我是個善變的人,說不定過幾天我就不想寫了😄,但希望自己能堅持用半年到一年的時間完成這本可能沒啥用的書。接下來開始自己的博客,先談談自己對XHR及相關標準,然后談談操作系統的I/0及Node的異步I/0。

網絡請求

XHR背景

網絡請求的這幾個標準和庫,其實沒有必要開一片博客來記錄下自己的想法和理解的,偶然和和同學說道這些網絡交互的標準或者是庫,有些歧義,我又去網上看看了一些人的博客想著是否可以糾正自己可能會是錯誤的理解,然后我就在網上不斷翻閱,按照我自己對自己寫的博客的標準來定義,我查閱到的這些博客都是一些不能入眼的內容,只是互聯網沒有自動垃圾回收的機制,無可厚非,我的理解或者我的博客一樣也會被別人理解為www的設計缺陷,但至少我愿意把一件事講清楚,給自己講清楚。最近開始籌劃并著手寫一本自己對于Node的理解及相關實戰項目的書,談及ajax時候,我寫了這樣一段話:

我在這段話中大肆吐槽了所謂的模塊或者框架用的很六的使用者。如果你沒有看過fetch的源碼實現,或者說你并沒有看過axios的源碼實現,你連攔截器是怎么定義的都不知道,你用的再六又能怎么樣尼?希望這段話在勉勵我自己的同時,也能觸及到看見我博客的志同道合的朋友。接下來我談一談我自己對于ajax、fetch、axios的個人理解。

ajax

ajax全稱是啥,看到這你能在腦海中反應出來么?異步的javascript和xml,英文:Asynchronous JavaScript and XML,是利用瀏覽器已有標準重新組合后的新技術標準,應該可以說ajax是web1.0到web2.0跨越的重大功臣之一。為什么這么說,ajax最直觀的特點就是通過請求與響應來局部刷新頁面,而不是說之前的必須通過表單進行一次整體的請求與響應,刷新整個頁面,浪費網絡資源,用戶體驗也極差。ajax有缺點么?或者說有哪些在以前全局刷新情況下能夠很容易實現的功能但是使用ajax后就變得比較繁雜尼?以下4點是我在網上尋到并深有同感的幾點,如下:

a. AJAX干掉了Back和History功能,即對瀏覽器機制的破壞

b. AJAX的安全問題

c. 對搜索引擎支持較弱

d. 違背URL和資源定位的初衷

現代瀏覽器的實現主要依靠XMLHttpRequest對象,因為瀏覽器的版本不同,帶來不對于XHR的兼容問題,那,看到這里,你可以立馬動手實現一個最原始的AJAX么?

  1. function loadXMLDoc() 
  2.  var xmlhttp; 
  3.  if (window.XMLHttpRequest) 
  4.  { 
  5.   //  IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執行代碼 
  6.   xmlhttp=new XMLHttpRequest(); 
  7.  } 
  8.  else 
  9.  { 
  10.   // IE6, IE5 瀏覽器執行代碼 
  11.   xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); 
  12.  } 
  13.  xmlhttp.onreadystatechange=function() 
  14.  { 
  15.   if (xmlhttp.readyState==4 && xmlhttp.status==200) 
  16.   { 
  17.    // 返回數據處理 
  18.    document.getElementById("myDiv").innerHTML=xmlhttp.responseText; 
  19.   } 
  20.  } 
  21.  
  22.  // 請求發送 true 異步,肯定異步啊,你要同步??? 
  23.  xmlhttp.open("GET","/try/ajax/ajax_info.txt",true); 
  24.  xmlhttp.send(); 

代碼我肯定不會一行一行講解的,這沒啥,就很簡單,但是onreadystatechange中的readyState以及status是值得關注的,其記錄著ajax的運行狀態以及響應狀態。onreadystatechange:每當 readyState 屬性改變時,就會調用該函數。readyState:存有XMLHttpRequest的狀態。從 0 到 4 發生變化,值對應的狀態如下:

0: 請求未初始化

1: 服務器連接已建立

2: 請求已接收

3: 請求處理中

4: 請求已完成,且響應已就緒

status:記錄著響應的狀態 200: "OK"、404: 未找到頁面等等

promise

接下來談談promise這個對象,用來干啥的,簡單說就是對JS異步編程的一種能力加持,讓異步代碼的編寫及閱讀不再那么的惡心人。我寫一段惡心人的簡單實例:

  1. setTimeout(()=>{ 
  2.  setTimeout(()=>{ 
  3.   setTimroiut(()=>{ 
  4.    ...... 
  5.   },1000) 
  6.     },1000) 
  7. },1000) 

你可能會說,啊這還好呀,這有啥。這只是我的一個簡單舉例,當在真實場景下無論前后端,不斷的異步嵌套的時候,你定會抓狂。那么,Promise是如何改善這種問題的尼?

將Promise理解為狀態扭轉機,類似于我們在學習編譯原理里面的有限狀態自動機,會由一個狀態過渡到另一個狀態,并且狀態是會結束的,有終點的。promise具有三種狀態,pending、resolve、reject。狀態的扭轉跟隨著兩過程:

pending ----> resolve

pending ----> reject

也就是從處理開始等待到成功處理或者從處理開始等待待處理失敗的過程。來看我直接markdown手擼把上面的嵌套promise化,讓代碼看起來更加直觀,流程更加清晰,讓其順序執行

  1. console.time(); 
  2. new Promise((resolve,reject)=>{ 
  3.  setTimeout(()=>{ 
  4.   if(Math.random() > 0.5){ 
  5.    resolve("timer1"); 
  6.   }else
  7.    reject("timer1 error"); 
  8.   } 
  9.    
  10.  },1000) 
  11. }).then((data)=>{ 
  12.  console.log(data); 
  13.  return new Promise((resolve, reject)=>{ 
  14.   setTimeout(()=>{ 
  15.    if(Math.random() > 0.5){ 
  16.     resolve("timer2"); 
  17.    }else
  18.     reject("timer2 error"); 
  19.    } 
  20.   },2000) 
  21.  }) 
  22.   
  23. }).then((data)=>{ 
  24.  console.log(data); 
  25.  return new Promise((resolve, reject)=>{ 
  26.   setTimeout(()=>{ 
  27.    if(Math.random() > 0.5){ 
  28.     resolve("timer3"); 
  29.    }else
  30.     reject("timer3 error"); 
  31.    } 
  32.   },2000) 
  33.  }) 
  34. }).catch((err)=>{ 
  35.  console.log(err); 
  36. }) 
  37. console.timeEnd() 

如果你的運氣夠好,每次都能random在0.5以下,那你就能看到 timer1,timer2,運氣不好直接就timer1 error了。為什么我在每個then里面都new了promise???感到奇怪?那就去看看mdn,then需要返回一個peomise對象。

promise還提供了race、all等靜態方法,用于串行或者并行執行,需要的自己下來看看,你也可以試試手擼一個promise,那你就很牛了。

fetch

講到了fetch,我說fetch其實就是ajax加一層promise的封裝,你贊同么?如果你贊同并且說這是一種polyfill,那我覺得你是完全懂fetch的使用方法并且明了其實現過程的,與其說fetch是promise對ajax進行了封裝,說的更準確一些的就是fetch是和ajax一樣同樣使用XMLHTTPRequest對象實現的各種http請求,然后使用promise進行了包裝使用.then.catch實現調用,但是其又與ajax稍有不同,為什么尼?因為其有屬于自己的實現方案,fetch的源碼,一共500多行,重點在其實現的幾個對象:Headers, Body, Request, Response,根據這幾個對象的命名就可以知道是對http結構及請求響應過程中的數據及方法的封裝,最后進行fetch方法的封裝。網上看到一個博主放了一段簡化的代碼,如下:

  1. (function (self) { 
  2.   'use strict'
  3.   if (self.fetch) { 
  4.      return 
  5.   } 
  6.   
  7.   // 封裝的 Headers,支持的方法參考https://developer.mozilla.org/en-US/docs/Web/API/Headers 
  8.   function Headers(headers) { 
  9.     ...... 
  10.   }   
  11.   
  12.   //方法參考:https://developer.mozilla.org/en-US/docs/Web/API/Body 
  13.   function Body() { 
  14.     ...... 
  15.   } 
  16.   
  17.   // 請求的Request對象 ,https://developer.mozilla.org/en-US/docs/Web/API/Request 
  18.   // cache,context,integrity,redirect,referrerPolicy 在MDN定義中是存在的 
  19.   function Request(input, options) { 
  20.      ...... 
  21.   } 
  22.   
  23.   Body.call(Request.prototype)  //把Body方法屬性綁到 Reques.prototype 
  24.   
  25.   function Response(bodyInit, options) { 
  26.   } 
  27.   
  28.   Body.call(Response.prototype) //把Body方法屬性綁到 Reques.prototype 
  29.   
  30.   self.Headers = Headers  //暴露Headers 
  31.   self.Request = Request //暴露Request 
  32.   self.Response = Response //暴露Response 
  33.   
  34.   self.fetch = function (input, init) { 
  35.     return new Promise(function (resolve, reject) { 
  36.       var request = new Request(input, init)  //初始化request對象 
  37.       var xhr = new XMLHttpRequest()  // 初始化 xhr 
  38.   
  39.       xhr.onload = function () { //請求成功,構建Response,并resolve進入下一階段 
  40.         var options = { 
  41.           status: xhr.status, 
  42.           statusText: xhr.statusText, 
  43.           headers: parseHeaders(xhr.getAllResponseHeaders() || ''
  44.         } 
  45.         options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL'
  46.         var body = 'response' in xhr ? xhr.response : xhr.responseText 
  47.         resolve(new Response(body, options)) 
  48.       } 
  49.   
  50.       //請求失敗,構建Error,并reject進入下一階段 
  51.       xhr.onerror = function () { 
  52.         reject(new TypeError('Network request failed')) 
  53.       } 
  54.   
  55.       //請求超時,構建Error,并reject進入下一階段 
  56.       xhr.ontimeout = function () { 
  57.         reject(new TypeError('Network request failed')) 
  58.       } 
  59.   
  60.       // 設置xhr參數 
  61.       xhr.open(request.method, request.url, true
  62.   
  63.       // 設置 credentials 
  64.       if (request.credentials === 'include') { 
  65.         xhr.withCredentials = true 
  66.       } else if (request.credentials === 'omit') { 
  67.         xhr.withCredentials = false 
  68.       } 
  69.   
  70.       // 設置 responseType 
  71.       if ('responseType' in xhr && support.blob) { 
  72.         xhr.responseType = 'blob' 
  73.       } 
  74.   
  75.       // 設置Header 
  76.       request.headers.forEach(function (value, name) { 
  77.         xhr.setRequestHeader(name, value) 
  78.       }) 
  79.       // 發送請求 
  80.       xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) 
  81.     }) 
  82.   } 
  83.   //標記是fetch是polyfill的,而不是原生的 
  84.   self.fetch.polyfill = true 
  85. })(typeof self !== 'undefined' ? self : this); // IIFE函數的參數,不用window,web worker, service worker里面也可以使用 

fetch本質意義上還是對XMLHttpRequest的請求封裝。

axios

談到axios時,這是我們經常會使用的一個網絡請求工具,易用且強大,提供了多種框架的版本,真是好,我還是貼一下axios的特性

1.從瀏覽器中創建XMLHttpRequests

2.從node.js創建http請求

3.支持PromiseAPI

4.攔截請求和響應

5.轉換請求數據和響應數據

6.取消請求

7.自動轉換JSON數據

8.客戶端支持防御XSRF

axios的源碼我還沒看完,沒有資格評論源碼級別的實現,但其就是promise對ajax的封裝,利用promise的能力來實現并行與串行的請求等,攔截器是一個很好的特性,允許我們在請求開始之前或者響應開始之前做一些我們想做的操作,這給業務層面的實現又多了其他的實現方案,說實話,我一開始一直覺得axios攔截器的實現是通過捕捉ajax的幾種狀態值并做響應的方法處理實現的,但是在閱讀部分源碼后我發現不是,原理是axios維護了一個攔截器方法數組,其實就是自定義方法,并使用use方法依次將攔截器數組里面的自定方法放在請求之前,利用promise形成鏈式調用,也就是順序調用來實現的。

I/O

I/O 背景

為啥又要講I/O了,事情是這樣的,上午時候跟一個自己尊敬的老師好友對一款桌面軟件的實現方案進行了討論,大致就是一款圖形處理兼AI推理的windows桌面應用,業務方要求必須使用c++完成所有的前后端開發工作,并且算子服務必須函數化在本地,于是我就開始了思考,給出了兩個實現方案,如下:

方案的思考過程中,我比較關注的兩個點是實現成本及軟件性能,之前寫過一篇對于端側性能的思考,尤其是這類需要做圖像處理,AI推理的應用,性能要求是極高的,當然,畢竟跑在windows上,而不是一些手機等終端上,GPU的調用十分的方便,性能也不會差到哪兒去,然后又基于實現方案的成本及可維護性做了思考,才給出了以上的兩種方案,談及到了I/O,這激起了我對異步I/O的思考。

異步I/O

說到異步編程,我相信這對于除開javascript以外的眾多語言都是比較陌生的,而且在絕大多數高級編程語言中,異步貌似不太被采納,大多數都喜歡利用從頭到腳同步阻塞的方式來執行,例如:PHP(哈哈哈,天下最好的語言),當然這樣利于邏輯的理解與實現,但是在復雜的應用中,阻塞那是不能想象的,可能你會說,我多線程啊,再進行線程通信不就好了,繼續看,看到這篇博客的人,一定是用過nginx的,為什么nginx會有如此高的性能表現,這得益于事件驅動,異步I/O的架構設計,在進行I/O的過程中,不用等待著上一個I/O執行完成才進行下一個步驟的執行。而Node的設計就與Nginx的事件驅動、異步I/O架構不能說一模一樣,但也90%一樣了。

前面我在吐槽PHP沒有異步I/O不能承載高并發應用時,PHPer會說,我為什么不能多線程并行執行來提高并發的能力,為什么非要異步I/O尼,無可厚非,如果創建多線程的開銷小于并行執行的開銷,那肯定多線程是首選,但是多線程就意味著你需要創建多個線程并且在多個線程之間來回切換會帶來巨大的開銷,通常來說,遇見比較復雜的應用,你還需要做到鎖的應用,以及狀態同步等問題,那么,異步I/O就能很好的解決這樣的問題,利用單線程,遠離多線層死鎖、狀態同步等問題,遠離阻塞,更好的利用CPU等。

異步I/O的執行過程

畫了張圖如下:

如上圖,異步I/O的精髓在于,單線程進行I/O處理時,并不會阻塞其它指令的執行,在完成處理后,通過callback完成數據返回。雖然上文一直在說異步與同步,但是對于操作系統內核來說,處理I/O只有阻塞與非阻塞之分,阻塞I/O就是調用I/O處理之后一定要等到系統內核層面完成操作后,調用才結束,才能往下執行,這就會造成CPU等待I/O執行完成,造成CPU使用空余,效率低下,而操作系統利用輪詢實現的非阻塞I/O能夠通過一系列機制來改善阻塞I/O,提升CPU使用效率及性能,這里我畫圖總結一下。應該來的更明顯直觀:

操作系統通過輪詢實現的非阻塞調用,能夠在貌似異步的情況下取的完整的I/O數據,但是對于應用程序而言,依然是同步的,因為CPU還是需要等待I/O的完全返回。理想的非阻塞異步I/O應該是應用程序發起非阻塞調用,而不是通過一些輪詢,遍歷機制來實現一種偽異步,現實中,實現真正的應用程序調用異步,使用了線層池方案,通過讓部分線程進行阻塞I/O或者非阻塞I/O加輪詢完成數據的獲取,讓一個線程來進行計算處理,通過線程間通信將I/O線程獲取的數據進行傳遞,實現異步I/O。這也是Node實現的異步I/O的底層方案。

Node 異步I/O

當然,Node實現了跨平臺的異步I/O,開發者在*nix及windwos異步I/O之上實現了Libuv來實現跨平臺,linux平臺自己實現了異步I/O,windows則采用了iocp實現,所以,我總說Node是機制創新,底層還是得益于C++的線程池異步I/O帶來的高性能

本文轉載自公眾號【QC的黑板報】,如需轉載請聯系作者!

 

責任編輯:姜華 來源: QC的黑板報
相關推薦

2021-07-12 06:11:14

SkyWalking 儀表板UI篇

2021-06-21 14:36:46

Vite 前端工程化工具

2021-01-28 08:55:48

Elasticsear數據庫數據存儲

2023-03-29 07:45:58

VS編輯區編程工具

2021-04-14 14:16:58

HttpHttp協議網絡協議

2021-04-08 11:00:56

CountDownLaJava進階開發

2022-03-22 09:09:17

HookReact前端

2021-07-21 09:48:20

etcd-wal模塊解析數據庫

2021-04-01 10:51:55

MySQL鎖機制數據庫

2021-03-12 09:21:31

MySQL數據庫邏輯架構

2022-02-17 08:53:38

ElasticSea集群部署

2022-04-29 14:38:49

class文件結構分析

2024-06-13 08:34:48

2021-10-28 08:51:53

GPIO軟件框架 Linux

2022-02-25 15:50:05

OpenHarmonToggle組件鴻蒙

2023-03-13 09:31:04

2021-07-08 07:30:13

Webpack 前端Tree shakin

2021-05-08 08:36:40

ObjectString前端

2021-04-23 08:59:35

ClickHouse集群搭建數據庫

2021-04-14 07:55:45

Swift 協議Protocol
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩不卡一区二区 | 一级黄在线观看 | 中文字幕亚洲精品 | 亚洲精品中文字幕av | 一区二区三区免费观看 | 久久精品国产清自在天天线 | 二区在线观看 | 午夜视频在线播放 | 污片在线免费观看 | 欧美自拍一区 | 色姑娘综合网 | 蜜臀av日日欢夜夜爽一区 | 亚洲精品一区中文字幕 | 亚洲成人在线网 | 国产免费福利小视频 | 中文字幕在线一区二区三区 | 一区二区影视 | 亚洲激情在线视频 | 成人二区三区 | 色婷婷一区二区三区四区 | 91视频网址| 国产黄色在线观看 | 欧美一区不卡 | 天天干com| 一区在线播放 | 精品伊人 | 亚洲天天干 | 在线视频91| 日韩精品在线看 | 中文字幕av一区二区三区 | 黄色网页在线 | 在线国产一区二区 | www.一级毛片 | 91网站在线看 | 欧美国产精品一区二区三区 | 红色av社区 | 喷潮网站| 亚洲综合色视频在线观看 | www.欧美视频 | 毛片a级| 涩涩视频网站在线观看 |