精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

萬字長文:關于sourcemap,這篇文章就夠了

開發 前端
sourcemap成為了房間里的大象,一旦出現諸如“無法映射到源文件”“只能映射到 loader 處理后的文件”等問題,多數人是毫無頭緒的;而就像 TJ 大神說的: "不要直接 copy 解決方案,要理解后自己去實現";

[[403568]]

 前言

而今,只要是工程化的項目,大多離不開 sourcemap 的身影,一言蔽之:構建處理前的代碼和處理后的代碼之間的橋梁。但卻很少有同學真的去深入了解它的運作原理,真問起來也就停留在“啊,有個.map 文件,可以通過它定位到源碼信息”,來,我們去瞅瞅,源碼是一句簡單的`console.log('好好學習,天天向上'`)的`.map`文件

圖片

如果我告訴你,位置信息就在mapping對應的這堆字母里

sourcemap成為了房間里的大象,一旦出現諸如“無法映射到源文件”“只能映射到 loader 處理后的文件”等問題,多數人是毫無頭緒的;而就像 TJ 大神說的: "不要直接 copy 解決方案,要理解后自己去實現";

閑言少敘,書歸正傳(不好意思,最近愛看評書),通過本文你將收獲什么呢?

本文目標

sourcemap配置項給你安排的明明白白,順帶送上生產環境、開發環境最佳實踐

sourcemap定位原理給你安排的明明白白,Base64-VQL是怎么做到生成mapping記錄源碼和處理后代碼間的映射

感恩大奉送,編碼給你安排的明明白白,base64 編碼、VLQ 編碼、base64-vlq 編碼的三世孽緣

讀至此處,您還要跑?

冰冰動圖大合集云盤,en,是不可能給的,就給一張你們瞅瞅好了

sourcemap:devTools 配置項二三事

對于sourcemap而言,我們最常見的,莫過于在 webpack 的配置項devTools中進行使用,而有多少種供我們選擇的配置呢?

圖片

也不多,二十種的樣子,好了,官網鏈接在此,大家去背吧,背完記得喊一聲,本文完。

抱歉我皮了,所謂變中取定,這么多種配置項其實只是五個關鍵字 eval、source-map、cheap、module 和 inline 的組合罷了,請牢記這張表,破陣心法,忽悠時方可娓娓道來。

怎么理解呢?實戰見真知。

舉例詳解

文件源碼如下

  1. let a = 1,b; 
  2. b = a; 

source-map 處理后輸出結果

  1. //# sourceMappingURL=bundle.js.map 

 

eval 處理后輸出結果

  1. eval("var a = 1,\n    b;\nb = a;\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/index.js\n// module id = 0\n// module chunks = 0\n\n//# sourceURL=webpack:///./src/index.js?"); 

 

解決問題:原作者解釋whyeval,關鍵在于下面兩句話

  • devtool: "source-map" cannot cache SourceMaps for modules and need to regenerate complete SourceMap for the chunk. It's something for production.
  • devtool: "eval-source-map" is really as good as devtool: "source-map", but can cache SourceMaps for modules. It's much faster for rebuilds.

翻譯來說劃重點:加 eval 和不加是一樣的🐂,但加了eval后可以緩存,于是更🐂。

Inline-source-map處理后輸出結果

  1. //# sourceMappingURL=data: ...(base64 字符串) 

 

cheap-source-map處理后輸出結果

  1. //# sourceMappingURL=bundle.js.map 

 

對于cheap-source-map而言,只會定義到出錯的這一行

而對于source-map而言,則會精準到列

存在的問題

  1. 錯誤信息只會定義到行,而不會定義到列
  2. 對于經由 babel 之類工具轉義的代碼,只能定位到轉換后的代碼

這就引出了我們最后的一個關鍵字

cheap-module-source-map處理后輸出結果

  1. //# sourceMappingURL=bundle.js.map 

 

測試代碼

  1. sum 
  2. let sum =  (a, b) => { 
  3.     return a + b 
  4. debugger 
  5. export default sum
  6. index.js 
  7. import sum from './sum'
  8. console.log(sum); 

對于cheap-source-map而言,此時頁面 debugger 展示源碼是 es5 的代碼,因為已經被 babal 轉義了

而對于source-map而言,則會精準到原始代碼

配置項關鍵字小結

至此,我們`source-map`的五個關鍵詞的學習也就告一段落了,而最開始提到官網給出的二十幾種配置無非是選詞組合而已,再附送下一些常見配置項的關鍵參數對比吧。

配置項最佳實踐

開發環境

  • 我們在開發環境對 sourceMap 的要求是:快(eval),信息全(module),
  • 且由于此時代碼未壓縮,我們并不那么在意代碼列信息(cheap),

所以開發環境比較推薦配置:devtool: cheap-module-eval-source-map

生產環境

  • 一般情況下,我們并不希望任何人都可以在瀏覽器直接看到我們未編譯的源碼,
  • 所以我們不應該直接提供 sourceMap 給瀏覽器。但我們又需要 sourceMap 來定位我們的錯誤信息,
  • 一方面 webpack 會生成 sourcemap 文件以提供給錯誤收集工具比如 sentry,另一方面又不會為 bundle 添加引用注釋,以避免瀏覽器使用。

這時我們可以設置devtool: hidden-source-map

至此,關于sourcemap在 webpack 中的應用層面我們就算是了解個七七八八了。但其實,這只是一個開頭小菜

本文最大目標來啦:sourcemap 到底怎么做到源文件和處理后文件映射的?

輸出內容分析:map 文件詳解

要分析實現,還是得先從現象下手,假定源文件script.js內容為

  1. let a=1; 
  2. let b=2; 
  3. let c=3; 

其輸出內容為

script-min.js

  1. var a=1,b=2,c=3; 

script-min.js.map

  1. {"version":3,"file":"script-min.js","lineCount":1,"mappings":"AAAA,IAAIA,EAAE,CAAN,CACIC,EAAE,CADN,CAEIC,EAAE;","sources":["script.js"],"names":["a","b","c"]} 

文件字段具體含義分析

 

可以看到,既然我們要定位,自然最關心的是具有【記錄位置信息】功能的 mapping 屬性,接下來詳細講解如何分析mapping。

mapping 屬性值含義

  • 【行對應】很好理解,即一個分號為一行,因為壓縮后基本上都是一行了,所以這個沒啥有用信息;
  • 【位置對應】可以理解為分詞,每個逗號對應轉換后源碼的一個位置;
  • 【分詞信息】是關鍵,如AAAA代表該位置轉換前的源碼位置,以VLQ編碼表示;

其中【分詞信息】每組最多五位(如果不是變量,只會有四位),分別是:

  • 第一位,表示這個位置在【轉換后代碼】的第幾列。
  • 第二位,表示這個位置屬于【sources 屬性】中的哪一個文件。
  • 第三位,表示這個位置屬于【轉換前代碼】的第幾行。
  • 第四位,表示這個位置屬于【轉換前代碼】的第幾列。
  • 第五位,表示這個位置屬于【names 屬性】的哪一個變量。

到此,我們也算是知道 map 文件到底是怎么組成的了。

小思考

Q:但為什么這么設定呢?理解絕對比死記更有效,其他都好理解,但談到分詞信息中的位置對應,我們下意識應該都會想到坐標,記錄組成元素在編譯后文件和源文件的坐標,就形成了映射;但我們看到的`mapping`卻是字符串,為什么?A:因為體積,如果直接坐標記錄信息,至少存在兩點空間損耗:編譯后文件的縱坐標大的驚人;因為坐標信息是數字,如果采用數組存儲,將有大量存儲空間浪費。注意上面的`version`字段,象征著版本,而對于現在的默認也是最新版`Source Map Revision 3.0`(V3)而言,通過使用 Base64 VLQ 編碼,大大縮小了.map 文件的體積,而這也是本文最有價值的思考點:`Base64 VLQ`是啥?為什么能做到縮減體積。

此處附送base64vlq 在線轉換地址,將上面的mappings對應的字符串輸入,將會得到對應的數字信息,如AAAA對應的是0000,這兩者之間的映射規則就是base64vlq編碼。

整理目標

到此,我們整理下接下來要做的事情,抬頭看天,低頭走路。

我們希望解決坐標信息占用空間過大的問題,主要在于兩點

  • 編譯后文件列號過大問題:因為會編譯成一行,可以想象靠后的元素縱坐標是很大的
  • 數據結構占據空間問題:數組自然比字符串更耗費空間

隨著對這兩個問題的思考,我們將會徹底理解,為啥我們用于記錄位置信息的mapping會是這個鬼樣子

  1. AAAA,IAAIA,EAAE,CAAN,CACIC,EAAE,CADN,CAEIC,EAAE 

打起精神,繼續學!冰冰續命

相對位置解決列號過大問題

對于第一點輸出后的位置元素的列號特別大的問題,可以采用相對位置的方案進行解決,具體規則如下

  • 第一次記錄的輸入位置和輸出位置是絕對的,往后的輸入位置和輸出位置都是相對上一次的位置移動了多少

舉例而言,假設 a.js 內容為feel the force,處理后輸出the force feel ,其 names 為:['feel','the','force'], source: ['a.js']

則其按照相對位置輸出的關系如下

| 字符組合 | 位置類別 | 輸出位置 | 輸入位置 | 映射(輸出 x | 屬于文件在 source 的索引 | 輸入 x | 輸入 y | 變量在 names 的索引) | | --- | --- | --- | --- | --- | | feel | 絕對 | 10, 0 | 0, 0 | 10 | 0 | 0 | 0 | 0 | | the | 相對 | -10, 0 | 5, 0 | -10 | 0 | 5 | 0 | 1 | | force | 相對 | 4, 0 | 4, 0 | 4 | 0 | 4 | 0 | 2 |

其中【位置類別】的相對代表相對上一個元素坐標的偏移,比如`the`的輸出位置相對于`feel`就是 x 軸左移 10,y 軸不變,所以其輸出位置為(-10, 0);其輸入位置是 x 軸右移 5,y 軸不變,所以其輸入位置為(5 ,0),`force`對比`the`類推即可。有心的小伙伴會發現【輸出 y 坐標】在映射中沒有記錄,其原因也很簡單,因為處理后的輸出代碼都是一行的,固定為 0,所以也就沒必要記錄了現在,我們就來到了第二點了,如何壓縮`mapping`?涉及到壓縮體積,便逃不掉編碼

就像上面說的,sourcemap 通過`Base64 VLQ`編碼進行了縮小.map 文件的體積的處理。那就開始琢磨下關鍵而神奇的`Base64 VLQ`吧

base64VLQ 解決數據結構占據空間問題

以坐標信息`[0,0,0,0], [4,0,0,4,0]`為例首先,我們得明確,對于源、目標文件的元素坐標映射關系,數組是不可能用數組的,這輩子是不可能用數組的,用字符串不香嗎?(原因就不解釋了)

[[403573]]

既然是字符串,原例就變成了`0,0,0,0 | 4,0,0,4,0` ,有沒有感覺這個`,`有點不順眼?本來它們就都是描述同一個映射關系,干嘛還浪費這空間,想想我們編譯后的那一大串,如果保留這個分隔符,別扭的很,那如何去掉呢?主角`Base64-VLQ`登場。Base64-VLQ 編碼見名知意,其實就是 VLQ 編碼方式和 base64 編碼的“一套組合拳”,它能去除分隔符主要在于 VLQ 編碼方式【變長】的特性,關鍵點就一句:用二進制表示,進行分組后每組最高位表示連續性,如果是 1,代表這組字節后面的一組字節也屬于同一個數;如果是 0,表示該數值到這就結束了。不明白?十臉懵逼?沒關系,咱一步步來。柿子挑軟的捏,要了解`Base64 VLQ`,咱就先查漏補缺下最熟悉的陌生人:`base64`編碼。

圖片

BASE64 編碼

我們開發同學最初了解到base64大概是在小icon圖標的處理上,當時了解到的是可以將圖片的二進制轉為文本,從而減少 http 請求,但只適用于小圖標等體積小的內容,因為使用base64編碼處理過會導致被處理對象體積增加 33%;那么base64到底是什么?它出現就是為了處理小圖標嗎?了解事物的經典三問

是什么?

在 MDN 中的定義:

  • 是一組相似的二進制到文本(binary-to-text)的編碼規則,使得二進制數據在解釋成 radix-64 的表現形式后能夠用 ASCII 字符串的格式表示出來。

為什么出現?

回想一下,有沒有遭遇過用記事本打開exe、jpg、pdf這些文件時,看到一大堆亂碼?很簡單,在 ASCII 碼中規定,031、127 這 33 個字符屬于控制字符,32126 這 95 個字符屬于可打印字符(來源于Unicode 官網),也就是說網絡傳輸、文本處理只能使用這 95 個字符,不在這個范圍內的字符無法使用。那么該怎么才能傳輸其他字符呢?這就就需要一個二進制到字符串的轉換方法。

怎么做到的?

編碼本身并不復雜,對使用者而言按圖索驥而已,關鍵是它規則為什么這么設定,以及修補規則出現的原因。

既然 ASCII 碼表中存在不可打印字符,那我們就定義一個新碼表,其范圍固定在可打印字符內。(這就意味著要多個新碼表字符表示一個 ASCII 碼表字符,原因很簡單,你要用蘋果、梨表示所有水果,那只好定義兩個蘋果是西瓜、兩個梨是番茄、一個蘋果一個梨是。。。排列組合)

新碼表字符的組成單元占幾個字節?

我們知道基礎 ASCII 碼,使用 7 位二進制數表示組成單元,新碼表的表示范圍小于 ASCII 碼表(因為要確保新碼表中都是可打印字符),這也就意味著,新碼表使用的二進制數必須少于七位,而二進制數越少代表其能表示的字符越少,那就需要更多個二進制數來表示一個字符,而這個位數應該是越多越好的,因為這樣我們所有的組成元素(新碼表)就多了,于是定 6 位吧。2^6 是 64,于是新碼表叫做 base64(這塊純屬于個人理解,僅供推理記憶,如有錯誤請不吝賜教)

如何 ASCII 碼進行 Base64 編解碼

ASCII 碼字符占 8 位二進制,而 Base64 占 6 位,取最小公倍數即為 24,即可以用 4 個 base64 字符去表示 3 個 ASCII 碼字符。遂有如下轉換規定

1.ASCII 碼字符串根據 ASCII 碼對照表轉換為二進制數值;

2.把二進制數值按每 6 位進行劃分;

  • 假設字符數是 3 的倍數,比如三個 ASCII 碼字符,就可以三個為一組,用四個 base64 字符來表示(3 * 8 == 4 * 6,enen,應該好理解的)
  • 如果待編碼字符串的長度不是 3 的倍數,則用 0 補位. 如果有連續 6 位都是 0 的話, 就用=來表示。

3.然后 6 位二進制轉化為十進制根據 Base64 對照表找到編碼字符.

對照表

擴展

在JavaScript中,原生提供了 base64 和 ASCII 碼之間的轉換 API

舉例而言

以 ASCII 的 A 字符為例,A 轉為二進制如上010000001,不足三位,所以補 0,從而補齊 24 位

再 6 位為一組,對照Base64 編碼表,全為 0 的話用=號代替

所以,得出結果,A 字符對應的 Base64 編碼是QQ==

至此,我們就算是對 base64 這位“最熟悉的陌生人”至少能答出個來龍去脈了

擴展-修補規則:URL 安全的 Base64 編碼

修補規則出現背景

Base64 編碼可用于在[HTTP](http://zh.wikipedia.org/wiki/HTTP)環境下傳遞較長的標識信息,然而,標準的 Base64 并不適合直接放在 URL 里傳輸,因為 URL 編碼器會把標準 Base64 中的「/」和「+」字符變為形如「%XX」的形式,而這些「%」號在存入數據庫時還需要再進行轉換,因為[ANSI](http://zh.wikipedia.org/wiki/ANSI) [SQL](http://zh.wikipedia.org/wiki/SQL)中已將「%」號用作通配符。咱證明下權威性,來看看`rfc`中的定義

  • For base 64, the non-alphanumeric characters (inparticular, "/") may be problematic in file names and URLs.

翻譯過來即:

  • 對于 base 64 編碼, 非字母表中的字符 (特別是 "/") 可能會在文件名和 URL 中出現問題

修補規則

為解決此問題,可采用一種**用于 URL 的改進 Base64**編碼,具體也很簡單,加密時先執行三條規則再轉`base64`即可(解密反之)

  • 不在末尾填充=號
  • + 用 *替換
  • / 用 -替換

擴展-實現:在JavaScript中如何實現base64url的編碼解碼?

編碼

  1. function urlsafe_b64encode(str) { 
  2.       base64Str = base64_encode(str); 
  3.       base64UrlStr = base64Str.replaceaLL('+','*').replaceaLL('/','-').replaceaLL('=',''); 
  4.       return base64UrlStr; 
  5.    } 

解碼

  1. function urlsafe_b64decode(base64UrlStr) { 
  2.       data = base64Str.replaceaLL('*','+').replaceaLL('-','/'); 
  3.        let mod4 = strlen(data) % 4; 
  4.        if (mod4) { 
  5.            data = data.substr('====', mod4); 
  6.        } 
  7.        return base64_decode(data); 
  8.     } 

有興趣的小伙伴可以使用處理 base64url 的 npm 包地址自行去驗證下哦

  1. # npm i base64url  
  2. const base64url = require('base64url'); 
  3. console.log('字符串     base64     base64URL'); 
  4. console.log(' A     ', encode('A'),'     ',base64url("A")); //  A      QQ==       QQ 

 圖片

VLQ 編碼

這是一個很陌生的詞匯,但卻是sourcemap實現的核心工具,還是老樣子,了解事物的經典三問

是什么?

  • VLQ 是 Variable-length quantity 的縮寫,變長編碼,用以通過任意位二進制精簡地表示很大的數值。

為什么出現?

縮減多數字組成的元素所占據的空間(比如按上文所生成的mapping,就是通過|進行區分不同數字的,這個|其實最好可以省掉,因為只是為了閱讀者好理解而已)

怎么做到的?

將數字轉化為二進制,然后規定通過二進制始末位具有標識數字的起始的特殊含義,從而節省分隔符所占的空間,設定如下:

一個二進制字節有 8 個位,在 VLQ 編碼中設定最高位為是否連續的標識,除了最高位,如果不足 7 個位的倍數則高位補 0;

對于大數字而言,需要多個單元進行表示,那么如果得知這幾個單元屬于同一個數字,編碼規則設定最高位表示連續性,如果是 1,代表這組字節后面的一組字節也屬于同一個數;如果是 0,表示該數值到這就結束了;這就避免了分隔符,如|,的出現

舉例而言

對于數字 7 和 1200 以及-7,如果用 VLQ 分別該怎么進行表示呢?

對 7 而言

  • 先判斷是不是七的倍數:不是,只有三位,所以前置位補 4 個 0;
  • 只有一個單元,自然最高位是 0(標識該數的結束);

得出的 VLQ 編碼就是0000111;

對于 1200 而言

  • 先判斷是不是七的倍數:不是,有 11 位,所以前置位補 3 個 0,處理對象變為00010010110000
  • 只有兩個單元,所以第一個單元最高位是 1(標識下一個單元還是表示該數),第二個單元是 0;

最后得到的結果即1000100100110000

到此,VLQ的編碼也算是告一段落了,其實就是一個規定,規定二進制某些位具有特定含義,從而節省空間,反正處理時按規定解碼就好了,也不需要人去看,再怎么難理解也是計算機的事兒,懶人改變世界嘛。

擴展一:VLQ 偏移自然數:Git 底層格式

在了解 VLQ 編碼的過程中,意外的了解到了很多冰山之下的知識,比如【VLQ 與自然數的相互轉換】在 Git 中居然有專門的實現的一個算法:雙射計數法(bijective numeration),主要是如何做到一一映射從而避免多字節 VLQ 的冗余現象,這個與本文主題相差有點大,不做過分拓展,推薦一篇文章《深扒 Git 底層格式:VLQ 偏移自然數》

擴展二:在JavaScript中如何實現 VLQ 的編碼?

  1. /**如何對數值進行 VLQ 編碼 * 1. 將數值改寫成二進制形式 10001001 * 2. 七位一組做分組,不足的補 0 * 3. 最后一組開頭補 0,其余補 1 * 4. 拼接 得出編碼 * @param {*} num  */function encodeForVLQ(num) {    let binary = num.toString(2);    let padded = binary.padStart(Math.ceil(binary.length / 7) * 7, '0');    let groups = padded.match(/\d{7}/g);     groups = groups.map((group,index)=>{          let pre = (index==0 && groups.length > 1?'1':'0')          return pre + group;      });    let vlqCode = groups.join('');    return vlqCode}console.log(encodeForVLQ2(7));console.log(encodeForVLQ2(1200)); 

至此,我們就完成了對 VLQ 編碼處理的了解,但我們可以發現輸出的是二進制數,而如果我們希望獲得的是字符串,就需要使用到BASE64 vlq編碼處理了

Base-VLQ 編碼

見名知意,其實就是 VLQ 編碼方式和 base64 編碼的結合。不過有幾點與 VLQ 的區別也需要注意一下

  • Base64 VLQ 需要能夠表示負數,于是用第一個單元的最后一位來作為符號標志位
  • 在 Base64 VLQ 中,因為要和 base64 相對應,所以修改vlq7 位一組的設定,改為 5 位一組,加上設定為最高位的連續位正好六位。

是什么?

對數字進行 VLQ 編碼處理后,使用 base64 字符表示 VLQ 編碼的結果。

為什么出現?

考慮到 mapping 文件的可閱讀和文本軟件處理的問題,VLQ 轉化后的二進制應該通過可打印字符去表示。

怎么做到的?

大致與 VLQ 編碼的處理邏輯相似,都是分組,然后用最高位表示連續,最關鍵的不同在于base64-vlq需要表示負數,于是用第一個單元的最后一位來作為符號標志位。

1.在 base64 中,將 VLQ 存儲單元是 8 個 btye 的設定改為 6 個,這樣就對應上了 base64 的存儲格式。

2.對于正負而言,編碼規則設定第一個單元的最后一位用于表示正負數,零正一負;

  • 這里需要注意,為什么說是【第一個單元】,因為一共六個位,去掉一個表示連續,一個表示正負,那能表示的范圍是[-15,15],如果數字過大,就會需要多個單元去描述(這也是說其變長的原因)非第一個單元是不需要表示正負的,所以只需要最高位表示是否終止即可。

3.將 VLQ 每個單元對應的 base64 字符存儲下來即可

舉例而言

對于數字 7 和 1200 以及-7,如果用base64-VLQ分別該怎么進行表示呢?

首先,對 7 而言

  • 只有一個單元,自然最高位是 0;
  • 正數,所以最后一位是 0;
  • 最后只有三位,所以前置位補 0;

得出的 VLQ 編碼就是001110;

其次,對于 1200 而言

先完成第一個單元

  • 多個單元,所以連續,最高位是 1;
  • 正數,所以最后一位是 0;
  • 超過一個單元,所以對于第一個單元在二進制中從后取出四個數出來填充四位即可

那得到的第一個單元的組成就是100000

再完成第二個單元

  • 還是填不滿,所以聯系,最高位是 1
  • 非第一個單元,所以不管正負了,取出五個數填充五位即可

得到的第二個單元的組成就是101011

例推下去,最后得到的結果即100000101011000010

 

根據mapping獲取信息

知道了 mapping 文件時如何來的,關鍵在于我們常見的場景是有類似AAAA,IAAIA,EAAE,CAAN,CACIC,EAAE,CADN,CAEIC,EAAE的 mapping 文件,那我們怎么從中獲取信息呢?很簡單,按照編碼方式反著來就好了,具體可見【擴展-解碼】的實現。

擴展:在JavaScript中如何實現base64-VLQ的編碼解碼?

在此實現一個簡易版本,其實目前有base64-vql的處理包,處理 vql 的 npm 包地址,其內部實現大多用到的是諸如>>> |之類的位運算,在此就不過分展開了,有機會單獨出一篇文章,思路是相似的。

編碼

  1. let base64 = [    'A''B''C''D''E''F''G''H''I''J''K''L''M''N''O''P',    'Q''R''S''T''U''V''W''X''Y''Z''a''b''c''d''e''f',    'g''h''i''j''k''l''m''n''o''p''q''r''s''t''u''v',    'w''x''y''z''0''1''2''3''4''5''6''7''8''9''+''/']; /**如何對數值進行 bae64-VLQ 編碼 * 1. 將數值改寫成二進制形式  * 2. 五位一組做分組,不足的補 0,并將組倒序排序 * 3. 最后一組開頭補 0,其余補 1 * 4. 轉 bae64 進制,即通過對應索引在 base64 碼表中取值  * @param {*} num  */function encode(num) {    //1. 改寫成二進制形式,如果是負數的話是絕對值轉二進制    let binary = (Math.abs(num)).toString(2);    //2.正數最后邊補 0,負數最右邊補 1,127 是正數,末位補 0     binary = num >= 0 ? binary + '0' : binary + '1';    //3.五位一組做分組,不足的補 0     let zero = 5 - (binary.length % 5);    if (zero > 0) {        binary = binary.padStart(Math.ceil(binary.length / 5) * 5, '0');    }    let parts = [];    for (let i = 0; i < binary.length; i += 5) {        parts.push(binary.slice(i, i + 5));    }    //4. 將組倒序排序     parts.reverse();    //5. 最后一組開頭補 0,其余補 1    for (let i = 0; i < parts.length; i++) {        if (i === parts.length - 1) {            parts[i] = '0' + parts[i];        } else {            parts[i] = '1' + parts[i];        }    }    //6. 轉 bae64 進制,即通過對應索引在 base64 碼表中取值     let chars = [];    for (let i = 0; i < parts.length; i++) {        chars.push(base64[parseInt(parts[i], 2)]);    }    return chars.join('')}let result = encode(137);console.log(result); 

解碼

  1. let base64 = [    'A''B''C''D''E''F''G''H''I''J''K''L''M''N''O''P',    'Q''R''S''T''U''V''W''X''Y''Z''a''b''c''d''e''f',    'g''h''i''j''k''l''m''n''o''p''q''r''s''t''u''v',    'w''x''y''z''0''1''2''3''4''5''6''7''8''9''+''/'];function getValue(char) {    let index = base64.findIndex(item => item == char);//先找這個字符的索引    let str = (index).toString(2);//索引轉成 2 進制    str = str.padStart(6, '0');//在前面補 0 補到 6 位    //最后一位是符號位,正數最后一位是 0,負數最后一位為 1    let sign = str.slice(-1)=='0'?1:-1;    //最后一組第一位為 0,其它的第一位為 1    str = str.slice(1, -1);    return parseInt(str, 2)*sign;}function decode(values) {    let parts = values.split(',');//分開每一個位置    let positions = [];    for(let i=0;i<parts.length;i++){        let part = parts[i];        let chars = part.split('');//得到每一個字符        let position = [];        for (let i = 0; i < chars.length; i++) {            position.push(getValue(chars[i]));//獲取此編寫對應的值        }        positions.push(position);    }    return positions;}let positions = decode('AAAA,IAAIA,EAAE,CAAN,CACIC,EAAE,CADN,CAEIC,EAAE');//后列,哪個源文件,前行,前列,變量 console.log('positions',positions);let offsets = positions.map(item=>[item[2],item[3],0,item[0],]);console.log('offsets',offsets);let origin = {x:0,y:0};let target = {x:0,y:0};let mapping=[];for(let i=0;i<offsets.length;i++){    let [originX,originY,targetX,targetY] = offsets[i];    origin.x += originX;    origin.y += originY;    target.x += targetX;    target.y += targetY;    mapping.push(`[${origin.x},${origin.y}]=>[${target.x},${target.y}]`);}console.log('mapping',mapping); 

有興趣的小伙伴可以使用處理 vql 的 npm 包地址自行去驗證下哦

  1. # npm i vlq const vlq = require('vlq');console.log(vlq.encode( 137 )); // yIconsole.log(vlq.decode( 'yI' )); // 137 

 圖片

關于base64-vlq的尾聲

到此,base64-VLQ的編碼也算是告一段落了,其實就是一個規定,規定二進制某些位具有特定含義,從而節省空間,反正處理時按規定解碼就好了,也不需要人去看,再怎么難理解也是計算機的事兒,懶人改變世界嘛。

尾聲

很喜歡《看見》,看來很多遍,其中一篇是《真實自有萬鈞之力》,大意講的是拍攝時要“去雕飾,去匠氣”,真正有價值的東西會自然而然的流露出來;研究 sourceMap 原理的過程中很“突兀”的想到了這句話,很多時候,我們對高大上的名詞趨之若鶩,卻很少思考一些像`sourcemap`這類實際解決痛點的“硬核”知識點置若罔聞,看到編碼就“累覺不愛”,老實講,要不是因為設定了交稿日期,我起碼還得拖個一兩周,因為看編碼實在是太太太煩了,又不常用,但堅持下來后才發現很多諸如`base64`、`ASCII`之類的知識點串聯成線,“通了”,大概很多小伙伴都或多或少有過這種類似頓悟的感覺,其實就算前端出了名的新知識點層出不窮,我們還是可以看到很多通用的、沉在冰山之下的“道”,而這,則需要靜下來去思考。

涉及到的工具

  • 處理 vql 的 npm 包地址
  • base64vlq 在線轉換

 

責任編輯:姜華 來源: 微醫大前端技術
相關推薦

2018-05-31 08:50:54

區塊鏈數字貨幣比特幣

2017-03-07 15:35:26

Android適配 界面

2017-03-10 21:04:04

Android適配

2019-10-31 09:48:53

MySQL數據庫事務

2021-10-18 11:58:56

負載均衡虛擬機

2022-09-06 08:02:40

死鎖順序鎖輪詢鎖

2017-03-30 22:41:55

虛擬化操作系統軟件

2021-01-19 05:49:44

DNS協議

2022-09-14 09:01:55

shell可視化

2021-11-10 07:47:48

Traefik邊緣網關

2017-12-12 12:53:09

2020-11-16 10:47:14

FreeRTOS應用嵌入式

2020-07-15 08:57:40

HTTPSTCP協議

2024-03-07 18:11:39

Golang采集鏈接

2022-07-19 16:03:14

KubernetesLinux

2020-07-09 07:54:35

ThreadPoolE線程池

2022-10-10 08:35:17

kafka工作機制消息發送

2020-10-13 07:44:40

緩存雪崩 穿透

2019-07-10 15:15:23

JVM虛擬機Java

2023-06-12 08:49:12

RocketMQ消費邏輯
點贊
收藏

51CTO技術棧公眾號

中文字幕精品无码亚| 国产二级一片内射视频播放| 日本中文字幕在线观看| 国产又粗又猛又爽又黄91精品| 精品国产一区av| 免费观看污网站| 日韩精品美女| 综合欧美亚洲日本| 国产一区二区三区黄| 精品国产xxx| 91九色精品国产一区二区| 精品久久人人做人人爽| 女性隐私黄www网站视频| 黄网页在线观看| 91在线高清观看| 国产深夜精品福利| 国产一级特黄视频| 凹凸成人精品亚洲精品密奴| 欧美成人欧美edvon| 无码人妻丰满熟妇区五十路百度| huan性巨大欧美| 久久精品综合网| 99在线观看视频| 性高潮视频在线观看| 欧美天天视频| 国产亚洲精品久久久久久| 一个人看的视频www| 日韩电影免费观看高清完整版| 综合久久综合久久| 蜜桃麻豆www久久国产精品| 国产免费的av| 日本午夜精品一区二区三区电影 | av资源久久| 精品国产一区a| 激情五月婷婷基地| 香蕉视频亚洲一级| 亚洲成a天堂v人片| 免费成人进口网站| 香蕉视频免费在线播放| 91在线精品一区二区三区| 超碰97国产在线| 一区二区视频网| 日韩综合在线视频| 91tv亚洲精品香蕉国产一区7ujn| 三级影片在线看| 欧美国产一级| 在线视频欧美性高潮| 久久丫精品国产亚洲av不卡| 中文字幕av一区二区三区四区| 欧美性色黄大片| 99久久激情视频| 黑人巨大精品欧美一区二区桃花岛| 亚洲制服丝袜av| a级片一区二区| 免费网站成人| 亚洲三级免费观看| 自拍另类欧美| 伦xxxx在线| 亚洲欧美视频一区| 大桥未久一区二区| av免费在线免费观看| 亚洲精品国产无套在线观| 日本xxx免费| 日韩精品卡一| 亚洲大片在线观看| 国产在线播放观看| 性xxxxfreexxxxx欧美丶| 婷婷综合另类小说色区| 美女av免费在线观看| 天堂中文av在线资源库| 色94色欧美sute亚洲13| 黄大色黄女片18第一次| 高清国产一区二区三区四区五区| 69堂国产成人免费视频| 中文字幕乱码在线人视频| 97久久亚洲| 日韩精品极品视频免费观看| 欧洲美一区二区三区亚洲 | 亚洲图片小说在线| 黄色免费在线观看网站| 亚洲国产综合人成综合网站| 国产特级淫片高清视频| 欧美性xxx| 欧美日韩高清不卡| 国产一级二级av| 台湾佬综合网| 中文字幕无线精品亚洲乱码一区| 国产日产精品一区二区三区的介绍| 牛牛国产精品| 91精品国产91久久久久久吃药| 特级毛片www| 久久成人av少妇免费| 高清日韩一区| 国产日韩精品在线看| 亚洲人精品午夜| 国产96在线 | 亚洲| 日韩中文视频| 欧美不卡在线视频| 精品国产无码在线观看| 伊人成综合网| 日韩美女视频中文字幕| 国产三级视频在线播放| 久久亚洲综合色一区二区三区| 伊人久久99| 在线天堂新版最新版在线8| 欧美日韩极品在线观看一区| 日本不卡视频一区| 波多野结衣在线观看一区二区三区| 久久成人免费视频| 男人日女人网站| 国产不卡视频一区| 欧美性bbwbbwbbwhd| 伊人在我在线看导航| 91豆麻精品91久久久久久| 中文字幕1区2区| 日韩国产欧美一区二区| 2024亚洲男人天堂| 国产女同91疯狂高潮互磨| 久久久精品蜜桃| 国产日韩亚洲欧美在线| 成人高清一区| 日韩大片在线观看视频| 国产白丝一区二区三区| 99国产精品久久久久久久| 亚洲free性xxxx护士hd| 国产在线网站| 大荫蒂欧美视频另类xxxx| 91精品国产高清91久久久久久| 日韩国产欧美| 国产精品久久久久久婷婷天堂| 视频午夜在线| 亚洲国产精品久久不卡毛片 | 成年永久一区二区三区免费视频 | 波多野结衣 在线| 亚洲国产日韩欧美一区二区三区| 亚洲自拍偷拍福利| 69av在线| 欧美四级电影网| 亚洲人成人无码网www国产| 99亚洲一区二区| 国产精品一 二 三| 性爱视频在线播放| 欧美一区二区在线看| 亚洲色图27p| 免费精品视频最新在线| 色阁综合av| 日韩欧美精品电影| 亚洲摸下面视频| 丰满人妻老熟妇伦人精品| 91在线免费播放| 日本黄色三级大片| 最新国产一区| 日韩av片电影专区| 青春有你2免费观看完整版在线播放高清 | 乱一区二区三区在线播放| 91资源在线观看| 日韩av中文字幕在线免费观看| 亚洲视频免费播放| 97超碰欧美中文字幕| 玩弄中年熟妇正在播放| 日韩欧美中文字幕电影| 欧美又大粗又爽又黄大片视频| 五月天久久久久久| 一本久道久久综合中文字幕| 女女互磨互喷水高潮les呻吟| 日韩成人精品在线观看| 中文网丁香综合网| 久久久久九九精品影院| 蜜臀久久99精品久久久无需会员 | 欧美 国产 精品| 亚洲国产视频二区| 97视频在线观看免费高清完整版在线观看 | 蜜桃精品视频在线| 在线观看三级网站| 成人春色在线观看免费网站| 欧美亚洲视频在线观看| 91亚洲欧美| 欧美一级夜夜爽| 亚洲国产成人精品激情在线| 久久免费视频一区| 国产亚洲视频一区| 一区在线免费观看| 欧美亚洲另类久久综合| 亚洲香蕉久久| 97色在线视频观看| 成人在线免费观看| 日韩欧美国产午夜精品| 国产又爽又黄的视频| 欧美激情在线看| 日本人dh亚洲人ⅹxx| 亚洲欧美成人| 麻豆md0077饥渴少妇| 日本午夜精品久久久| 国产乱肥老妇国产一区二| 免费av不卡在线观看| 国产亚洲视频在线观看| 精品国产18久久久久久| 色av综合在线| 久久97人妻无码一区二区三区| 极品人妻一区二区| 久久视频一区| 国产一二三区在线播放| 狠狠色狠狠色综合婷婷tag| 999国内精品视频在线| 欧美激情喷水| 久久久久久久国产精品视频| h视频网站在线观看| 亚洲国产精品va在看黑人| 一级久久久久久久| 黄色91在线观看| 国产成人久久久久| 久久久久成人黄色影片| 国产人妖在线观看| 蓝色福利精品导航| 黑人糟蹋人妻hd中文字幕| 欧美日韩精品免费观看视频完整| 日韩一区二区三区资源| 伦理一区二区| 91中文字精品一区二区| 久久av日韩| 欧美中文字幕精品| 久久大胆人体| 免费91麻豆精品国产自产在线观看 | 国产在线观看成人| 日韩毛片精品高清免费| 一区二区伦理片| 99国产精品久| 看全色黄大色黄女片18| 国产精品一区在线| 中文字幕日韩综合| 蜜桃av噜噜一区| 激情婷婷综合网| 国产日韩欧美三级| 成年人网站国产| 国产精品a久久久久| 三年中国中文在线观看免费播放 | 男人日女人的bb| 久久精品国内一区二区三区水蜜桃| 日本一区视频在线观看| 国产精品入口久久| 欧美二区在线| 竹菊久久久久久久| 久久综合给合久久狠狠色| 成人午夜大片| 国产综合精品一区二区三区| 91亚洲无吗| 国产精品夜夜夜一区二区三区尤| 中文字幕久久精品一区二区| 91中文字精品一区二区| 中文字幕一区二区三区日韩精品 | 亚洲成在人线免费观看| 国产一区免费在线| 日韩大胆成人| 欧美日韩一区二| 红桃成人av在线播放| 天天好比中文综合网| 欧美日一区二区| 一区二区三区不卡在线| 五月婷婷六月综合| 欧美做受777cos| 亚洲激情午夜| 免费黄色福利视频| 全国精品久久少妇| 中国黄色片一级| 成人综合婷婷国产精品久久蜜臀| 国产a√精品区二区三区四区| 成人性生交大片免费看中文网站| 91精产国品一二三| 91亚洲精品久久久蜜桃| 国产精品高清无码在线观看| 中文字幕av在线一区二区三区| av黄色免费在线观看| 一区二区久久久| 日韩欧美中文字幕一区二区| 色综合视频一区二区三区高清| 一区二区乱子伦在线播放| 91精品一区二区三区久久久久久| 亚洲欧美激情在线观看| 精品亚洲精品福利线在观看| yourporn在线观看视频| 另类色图亚洲色图| ****av在线网毛片| 国产精品久久久91| 清纯唯美激情亚洲| 粉嫩av一区二区三区免费观看| 久久av免费看| 好吊色视频988gao在线观看| 国产精品一国产精品k频道56| 国产嫩草在线观看| 国产成人综合在线| 极品人妻一区二区三区| 国产精品国产精品国产专区不片| 国产一级一级片| 欧美视频完全免费看| 亚洲精品免费在线观看视频| 亚洲欧洲在线视频| www免费视频观看在线| 2019精品视频| 国产一区二区三区视频在线| 免费久久久一本精品久久区| 一区二区在线影院| 国产精品亚洲二区在线观看 | 亚洲xxx视频| 国产一区二区三区91| 欧美日韩激情四射| 日本女优在线视频一区二区| 性欧美18—19sex性高清| 中文字幕的久久| 日韩av在线电影| 538prom精品视频线放| 免费看男男www网站入口在线| 欧美精品免费看| 欧美精品总汇| 激情久久av| 欧美喷水视频| 久久撸在线视频| 久久蜜桃av一区二区天堂| 精品在线视频免费| 在线播放中文字幕一区| 精品影院一区| 992tv成人免费视频| 婷婷综合国产| 9999在线观看| 免费观看日韩电影| 成人性生交大免费看| 无码av中文一区二区三区桃花岛| 国产喷水吹潮视频www| 中文字幕免费精品一区| 自拍视频在线看| 国产日韩在线一区二区三区| 亚洲色图二区| 97超碰人人爽| 国产精品久久久久久久久搜平片| 无码人妻黑人中文字幕| 亚洲国产一区自拍| 国产网红在线观看| 999视频在线免费观看| 天堂网在线观看国产精品| 亚洲欧美视频二区| 国产精品女主播av| 亚洲天堂aaa| 正在播放欧美一区| 91大神在线观看线路一区| 日韩福利影院| 免费成人av在线| 五月天精品在线| 欧美日韩一区二区欧美激情| 成人高清免费在线播放| 国产精品日日摸夜夜添夜夜av| 国产日产一区| 久久久精品麻豆| 国产精品三级视频| 一级黄色小视频| 欧美美最猛性xxxxxx| 免费一级欧美在线大片| 97在线免费视频观看| 成人高清在线视频| 久久一区二区三区视频| 日韩精品一区二区三区第95| 亚洲女同av| 日韩国产伦理| 精品在线一区二区三区| 99久久婷婷国产综合| 日韩精品一区二区三区在线观看 | 韩国三级视频在线观看| 午夜精品福利久久久| 亚洲三区在线观看无套内射| 日韩美女福利视频| 午夜影院欧美| 在线播放av网址| 精品女同一区二区三区在线播放| 日本亚洲欧美| 国产色视频一区| 伊人天天综合| 美女爆乳18禁www久久久久久| 欧美日本国产视频| 欧洲一区二区三区| 欧美成熟毛茸茸复古| 青青草国产精品97视觉盛宴| 午夜国产福利一区二区| 亚洲精品久久在线| 欧美高清你懂的| 人妻少妇精品久久| 国产午夜精品久久久久久免费视 | 亚洲美女在线视频| 青娱乐极品盛宴一区二区| 成人免费看片'免费看| 91蜜桃婷婷狠狠久久综合9色| 在线观看黄色网| 国内偷自视频区视频综合| 精品72久久久久中文字幕| 亚洲色图欧美自拍| 午夜日韩在线观看| 三级外国片在线观看视频| 国产精品国色综合久久| 久久亚洲美女| 久久久久亚洲av片无码下载蜜桃| 亚洲色图15p| 51亚洲精品| 欧美成人福利在线观看|