<dfn id="hx5t3"><strike id="hx5t3"><em id="hx5t3"></em></strike></dfn>

    <thead id="hx5t3"></thead><nobr id="hx5t3"><font id="hx5t3"><rp id="hx5t3"></rp></font></nobr>

    <listing id="hx5t3"></listing>

    <var id="hx5t3"></var>
    <big id="hx5t3"></big>

      
      

      <output id="hx5t3"><ruby id="hx5t3"></ruby></output>
      <menuitem id="hx5t3"><dfn id="hx5t3"></dfn></menuitem>

      <big id="hx5t3"></big>

        kruz

        kruz 查看完整檔案

        上海編輯武漢紡織大學  |  軟件工程 編輯  |  填寫所在公司/組織填寫個人主網站
        編輯
        _ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 個人簡介什么都沒有

        個人動態

        kruz 贊了文章 · 3月7日

        JS 文件互轉、10 個 HTML 文件上傳技巧、Web 用戶體驗設計提升指南、奇怪的知識——位掩碼 | 思否技術周刊

        今日分享提升工作幸福感的知識點,希望大家不要錯過這些好文~

        1、JS 文件 base64、File、Blob、ArrayBuffer 互轉

        二進制互轉

        1. file對象轉base64
        let?reader?=?new?FileReader();
        ?reader.readAsDataURL(file[0])
        ?console.log(reader)
        1. base64 轉成blob 上傳
        function?dataURItoBlob(dataURI)?{??
        ????var?byteString?=?atob(dataURI.split(',')[1]);??
        ????var?mimeString?=?dataURI.split(',')[0].split(':')[1].split(';')[0];??
        ????var?ab?=?new?ArrayBuffer(byteString.length);??
        ????var?ia?=?new?Uint8Array(ab);??
        ????for?(var?i?=?0;?i?<?byteString.length;?i++)?{??
        ????????ia[i]?=?byteString.charCodeAt(i);??
        ????}??
        ????return?new?Blob([ab],?{type:?mimeString});??
        }
        1. blob 轉成ArrayBuffer
        let?blob?=?new?Blob([1,2,3,4])
        let?reader?=?new?FileReader();
        reader.onload?=?function(result)?{
        ????console.log(result);
        }
        reader.readAsArrayBuffer(blob);
        1. buffer 轉成blob
        let?blob?=?new?Blob([buffer])
        1. base64 轉 file
        const?base64ConvertFile?=?function?(urlData,?filename)?{?//?64轉file
        ??if?(typeof?urlData?!=?'string')?{
        ????this.$toast("urlData不是字符串")
        ????return;
        ??}
        ??var?arr?=?urlData.split(',')
        ??var?type?=?arr[0].match(/:(.*?);/)[1]
        ??var?fileExt?=?type.split('/')[1]
        ??var?bstr?=?atob(arr[1])
        ??var?n?=?bstr.length
        ??var?u8arr?=?new?Uint8Array(n)
        ??while?(n--)?{
        ????u8arr[n]?=?bstr.charCodeAt(n);
        ??}
        ??return?new?File([u8arr],?'filename.'?+?fileExt,?{
        ????type:?type
        ??});
        }

        2、10 個 HTML 文件上傳技巧

        上傳文件功能可以說是項目經常出現的需求。從在社交媒體上上傳照片到在求職網站上發布簡歷,文件上傳無處不在。在本文中,我們將討論 HTML文件上傳支持的10種用法,希望對你有用。

        1. 單文件上傳

        我們可以將input 類型指定為file,以在Web應用程序中使用文件上傳功能。

        <input?type="file"?id="file-uploader">

        input filte 提供按鈕上傳一個或多個文件。默認情況下,它使用操作系統的本機文件瀏覽器上傳單個文件。成功上傳后,File API?使得可以使用簡單的 JS 代碼讀取File對象。要讀取File對象,我們需要監聽?change事件。

        首先,通過id獲取文件上傳的實例:

        const?fileUploader?=?document.getElementById('file-uploader');

        然后添加一個change?事件偵聽器,以在上傳完成后讀取文件對象, 我們從event.target.files屬性獲取上傳的文件信息:

        fileUploader.addEventListener('change',?(event)?=>?{
        ??const?files?=?event.target.files;
        ??console.log('files',?files);
        });

        在控制臺中觀察輸出結果,這里關注一下FileList數組和File對象,該對象具有有關上傳文件的所有元數據信息。

        clipboard.png

        如果大家看到這里,有點激動,想手賤一下,可以 CodePen 玩玩,地址:

        https://codepen.io/atapas/pen...

        2. 多文件上傳

        如果我們想上傳多個文件,需要在標簽上添加 multiple 屬性:

        <input?type="file"?id="file-uploader"?multiple?/>

        現在,我們可以上傳多個文件了,以前面事例為基礎,選擇多個文件上傳后,觀察一下控制臺的變化:

        clipboard.png

        如果大家看到這里,有點激動,想手賤一下,可以 CodePen 玩玩,地址:

        https://codepen.io/atapas/pen...

        3.了解文件元數據

        每當我們上傳文件時,File對象都有元數據信息,例如file name,size,last update time,type 等等。這些信息對于進一步的驗證和特殊處理很有用。

        const fileUploader = document.getElementById('file-uploader');
        
        //?聽更?change?件并讀取元數據
        fileUploader.addEventListener('change',?(event)?=>?{
        ??//?獲取文件列表數組
        ??const?files?=?event.target.files;
        ??//?遍歷并獲取元數據
        ??for?(const?file?of?files)?{
        ????const?name?=?file.name;
        ????const?type?=?file.type???file.type:?'NA';
        ????const?size?=?file.size;
        ????const?lastModified?=?file.lastModified;
        ????console.log({?file,?name,?type,?size,?lastModified?});
        ??}
        });

        下面是單個文件上傳的輸出結果:

        clipboard.png

        如果大家看到這里,有點激動,想手賤一下,可以 CodePen 玩玩,地址:

        https://codepen.io/atapas/pen...

        4.了解?accept?屬性

        我們可以使用accept屬性來限制要上載的文件的類型,如果只想上傳的文件格式是 .jpg,.png 時,可以這么做:

        <input?type="file"?id="file-uploader"?accept=".jpg,?.png"?multiple>

        在上面的代碼中,只能選擇后綴是.jpg和.png的文件。

        如果大家看到這里,有點激動,想手賤一下,可以 CodePen 玩玩,地址:

        https://codepen.io/atapas/pen...

        5. 管理文件內容

        成功上傳文件后顯示文件內容,站在用戶的角度上,如果上傳之后,沒有一個預覽的,就很奇怪也不體貼。

        我們可以使用FileReader對象將文件轉換為二進制字符串。然后添加load?事件偵聽器,以在成功上傳文件時獲取二進制字符串。

        //?FileReader?實例
        const?reader?=?new?FileReader();
        fileUploader.addEventListener('change',?(event)?=>?{
        ??const?files?=?event.target.files;
        ??const?file?=?files[0];
        ??reader.readAsDataURL(file);
        ??reader.addEventListener('load',?(event)?=>?{
        ????const?img?=?document.createElement('img');
        ????imageGrid.appendChild(img);
        ????img.src?=?event.target.result;
        ????img.alt?=?file.name;
        ??});
        });

        如果大家看到這里,有點激動,想手賤一下,可以 CodePen 玩玩,地址:

        https://codepen.io/atapas/pen...

        文章后面還有五個技巧分享,分別是:

        6.驗證文件大小

        1. 顯示文件上傳進度
        2. 怎么上傳目錄上傳?
        3. 拖拽上傳
        4. 使用objectURL處理文件

        可以點擊標題鏈接,去原文章瀏覽全部技巧~

        3、前端優秀實踐不完全指南

        本文應該叫,Web 用戶體驗設計提升指南。

        一個 Web 頁面,一個 APP,想讓別人用的爽,也就是所謂的良好的用戶體驗,我覺得他可能包括但不限于:

        • 急速的打開速度
        • 眼前一亮的 UI 設計
        • 酷炫的動畫效果
        • 豐富的個性化設置
        • 便捷的操作b
        • 貼心的細節
        • 關注殘障人士,良好的可訪問性
        • ...

        所謂的用戶體驗設計,其實是一個比較虛的概念,是秉承著以用戶為中心的思想的一種設計手段,以用戶需求為目標而進行的設計。設計過程注重以用戶為中心,用戶體驗的概念從開發的最早期就開始進入整個流程,并貫穿始終。

        良好的用戶體驗設計,是產品每一個環節共同努力的結果。

        除去一些很難一蹴而就的,本文將就頁面展示、交互細節、可訪問性三個方面入手,羅列一些在實際的開發過程中,積攢的一些有益的經驗。通過本文,你將能收獲到:

        1. 了解到一些小細節是如何影響用戶體驗的
        2. 了解到如何在盡量小的開發改動下,提升頁面的用戶體驗
        3. 了解到一些優秀的交互設計細節
        4. 了解基本的無障礙功能及頁面可訪問性的含義
        5. 了解基本的提升頁面可訪問性的方法

        4、13個頂級免費所見即所得文本編輯器工具

        CKEditor

        CKEditor擁有10多年的開發經驗,你可以完全放心此文本編輯器的質量。它支持70多種語言,我認為這是你網站的不錯選擇。它還可以運行在許多不同的瀏覽器上,并能很好地與大多數前端框架,如reat,vue,angular......你可以使用CDN直接嵌入到你的HTML頁面中......。目前它有兩個版本并行運行的CKEditor4和CKEditor5,根據不同的使用目的,你會選擇適合自己的編輯器。

        https://ckeditor.com/

        Trumbowyg

        Trumbowyg是針對HTML5優化的代碼編輯器,它支持大多數流行的瀏覽器,例如IE9 +,Firefox,Chrome等。據我所知,它包含用于文本編輯的所有工具,僅為20Kb,它輕巧,將幫助你的網站更流暢地運行。此外,它還具有其他支持插件來幫助你更好地工作,例如插入表情符號,其他國家/地區的支持語言,添加聲音,插入特殊字符...

        https://alex-d.github.io/Trumbowyg/

        TinyMCE

        TinyMCE 5是一款編輯器,它能讓你靈活地編輯、添加或刪除本程序中的部分內容。除了基本的編輯器,那么我發現它還提供了很多支持,更好的用戶體驗,如添加評論,測試檢查路徑,提供優質的圖標和界面,檢查拼寫的內容...... 然而,這也是它的弱點,因為如果你想使用高級工具,你必須每月支付約25美元。

        https://www.tiny.cloud/features/

        Quill

        Quill是一個開放源代碼編輯器,因此可以將其用于所有類型的商業或非商業網站。它有很多功能,如添加鏈接,圖像,視頻或添加代碼片段的內容…關于Quill,我最喜歡的一點是它的簡單設置和顯示,可以在多設備屏幕上的所有現代的、響應迅速的web瀏覽器上顯示,還有使用它的常見問題的詳細說明。

        https://quilljs.com/

        Trix

        Trix是一個開源的編輯器,可以讓你在Web中輕松地撰寫消息、寫評論、寫帖子......,并被良好編程的平板電腦使用。如果你只需要創建內容所需的功能,那么Trix同樣是不錯的選擇。

        https://trix-editor.org/

        Jodit Editor 3

        Jodit Editor 3是一個用純TypeScript編寫的開源github編輯器,不使用任何其他庫。它允許你以多種方式設置它,如通過npm、使用CDN......。我喜歡它的是,除了詳細的說明,還有一個程序,通過代碼讓我們自由選擇哪些工具附加到Jodit Editor。

        https://xdsoft.net/jodit/

        Summernote

        Summernote是GitHub上的開源編輯器,獲得了超過9K星。它是通過Bootstrap框架設計的,具有在你的網站上創建內容所需的所有功能。你只需要下載它的源文件css,js,再加上Bootstrap框架(也支持3、4兩個版本)就已經可以為你的網站服務了。

        https://summernote.org/

        Editor.js

        Editor.js是一個開源的塊狀編輯器,它不會像普通的編輯器那樣使用標簽HTML,將內容以JSON的形式輸出,使其更容易管理。它還支持通過使用API的插件,多虧了這一點,應該任何功能 任何開發者都可以為這個程序貢獻更多有趣和有用的插件。

        https://editorjs.io/

        MediumEditor

        MediumEditor是Medium的內置的開放源代碼編輯器,用于人們博客。它僅包含編輯器所需的基本實用程序,因此僅約28kB,這將有助于你的網站得到優化。同時如果我們想要添加其他功能,為了優化編輯,MediumEditor還提供了額外的外部實用工具,定期更新。

        https://yabwe.github.io/medium-editor/

        Wysihtml

        Wysihtml是一個由Voog團隊構建的開源編輯器。它功能齊全,可以幫助你輕松編輯文本,并且支持大多數現代屏幕瀏覽器的設備圖像。有很多工具我很喜歡它是自動轉換不合適的HTML標簽率,自動分析內容時從Word, PDF,顯示內容為HTML…

        http://wysihtml.com/

        ContentTools

        ContentTools是內置的開源編輯器,可幫助你輕松地一種方式編輯HTML內容。它提供了用于編輯內容的各種實用程序,你還可以輕松地將Message Institute和其他實用程序添加到程序中(請參閱脫機API部分)。我還發現了如何設置,添加或刪除程序中的函數的文章…都是非常細致的。

        https://getcontenttools.com/demo

        Froala

        Froala是一個編輯器,可以很容易地為網站設置,并允許你根據預期用途打開廣泛的功能。由于它是用純JavaScript編寫的,因此你可以將其用于當今的大多數現代前端框架。它還提供了許多有用的工具,以及編輯圖像,添加或編輯視頻,添加圖標,管理面板等。但是,如果你要使用該工具用于商業目的,則必須購買許可證。

        https://froala.com/wysiwyg-editor/tour/

        Redactor

        Redactor是一款功能齊全的編輯器,具有精美而簡單的設計。超過9年的發展,包括很多支持插件,我想這是一個很好的產品。另外它對程序員在使用程序的過程中遇到的每一個常見問題都有極其詳細的實例。但是,它也有一個缺點,當你將其用于商業目的時必須購買許可證。

        https://imperavi.com/redactor/

        5、奇怪的知識——位掩碼

        假設我們有一個權限系統,它通過 JSON 的方式記錄了某個用戶的權限開通情況(姑且假設權限集是 CURD):

        const?permission?=?{
        ??create:?false,
        ??update:?false,
        ??read:?true,
        ??delete:?false,
        }

        如果我們把 false 寫成 0,true 寫成 1,那么這個 permisson 對象可以簡寫為?0b0010。

        const?permission?=?{
        ??create:?false,
        ??update:?false,
        ??read:?true,
        ??delete:?false,
        }
        //?從左往右,依次為?create,?update,?read,?delete?所對應的值
        const?permissionBinary?=?0b0010

        對于 JSON 對象的權限集,如果我們要查看或者修改該用戶的某些權限,只需要通過形如 permission.craete 的普通對象操作即可。那么如果對于二進制形式的權限集,我們又應該如何進行查看或者修改的操作呢?接下來我們就開始使用奇怪的知識——位掩碼來進行了。

        位掩碼

        首先進行名詞解釋,什么是”位掩碼“。

        位掩碼(BitMask),是”位(Bit)“和”掩碼(Mask)“的組合詞?!蔽弧爸复M制數據當中的二進制位,而”掩碼“指的是一串用于與目標數據進行按位操作的二進制數字。組合起來,就是”用一串二進制數字(掩碼)去操作另一串二進制數字“的意思。

        明白了位掩碼的作用以后,我們就可以通過它來對權限集二進制數進行操作了。

        1、查詢用戶是否擁有某個權限

        已知用戶權限集二進制數為 permissionBinary = 0b0010。如果我想知道該用戶是否存在?update?這個權限,可以先給定一個位掩碼?mask = 0b1。

        image.png

        由于 update 位于右數第三項,所以只需要把位掩碼向左移動兩位,剩余位置補0。最后和權限集二進制數進行按位與運算即可得到結果。

        image.png

        最后算出來的 result 為?0b0000,使用 Boolean()?函數處理之即可得到 false 的結果,也就是說該用戶的 update 權限為 false。

        //?從左往右,依次為?create,?update,?read,?delete?所對應的值
        const?permissionBinary?=?0b0010
        //?由于?update?位于右數第三位,因此只需要讓掩碼向左移動2位即可
        const?mask?=?0b1?<<?2
        const?result?=?permissionBinary?&?mask
        Boolean(result)?//?false

        2、修改用戶的某個權限

        當我們明白了如何用位掩碼來查詢權限后,要修改對應的權限也就手到擒來了,無非就是換一種位運算。假設還是?update?權限,如果我想把它修改成?true,我們可以這么干:

        image.png

        只需要把按位與改為按位異或即可,代碼如下:

        //?從左往右,依次為?create,?update,?read,?delete?所對應的值
        const?permissionBinary?=?0b0010
        //?由于?update?位于右數第三位,因此只需要讓掩碼向左移動2位即可
        const?mask?=?0b1?<<?2
        const?result?=?permissionBinary?^?mask
        parseInt(result).toString(2)?//?0b0110

        經過上面的內容,相信你已經基本掌握了位掩碼的知識,同時你肯定還有很多問號,比如說這么復雜又不好閱讀的代碼,真的有意義嗎?

        臟數據記錄

        前文例子中的權限系統僅有區區4個數據的處理,位掩碼技術顯得復雜又小題大做。那么有沒有什么場景是真的適合使用位掩碼的呢?臟數據記錄就是其中一個。

        假設我們存在著一份原始數據,其值如下:

        let?A?=?'a'
        let?B?=?'b'
        let?C?=?'c'
        let?D?=?'d'

        給定一個二進制數,從左往右分別對應著 A/B/C/D 的狀態:

        let?O?=?0b0000?//?十進制?0

        則數據一旦發生了修改,都可以用對應的比特位來表示

        //?當且僅當?A?發生了修改
        O?=?0b1000?//?十進制?8
        //?當且僅當?B?發生了修改
        O?=?0b0100?//?十進制?4
        //?當且僅當?C?發生了修改
        O?=?0b0010?//?十進制?2
        //?當且僅當?D?發生了修改
        O?=?0b0001?//?十進制?1

        同理,當多個數據發生了修改時,則可以同時表示

        //?當?A?和?B?發生了修改
        O?=?0b1100?//?十進制?12
        //?當?A/B/C?都發生了修改
        O?=?0b1110?//?十進制?14

        通過這個思路,應用排列組合的思想,可以很快知道只需要僅僅 4 個比特位,就可以表達 16 種數據變化的情況。由于二進制和十進制可以相互轉化,因此只需要區區 16 個十進制數,就可以完整地表達 A/B/C/D 這四個數據的變化情況,也就是臟數據追蹤。舉個例子,給定一個臟數據記錄 14,二進制轉換為?0b1110,因此表示 A/B/C 的數據被修改了。

        Svelte 這個框架,就是通過這個思路來實現響應式的:

        if?(?A?數據變了?)?{
        ??更新A對應的DOM節點
        }
        if?(?B?數據變了?)?{
        ??更新B對應的DOM節點
        }
        /**?轉化成偽代碼?**/
        if?(?dirty?&?8?)?{?//?8?===?0b1000
        ??更新A對應的DOM節點
        }
        if?(?dirty?&?4?)?{?//?4?===?0b0100
        ??更新B對應的DOM節點
        }

        老鼠喝毒藥

        除了用來做臟數據記錄以外,位掩碼也能夠用來處理經典的”老鼠喝毒藥“的問題。

        有 1000 瓶水,其中有一瓶有毒,小白鼠只要嘗一點帶毒的水24小時后就會死亡,問至少要多少只小白鼠才能在24小時內鑒別出哪瓶水有毒?

        我們簡化一下問題,假設只有 8 瓶水,其編號用二進制表示:

        image.png

        接著按照圖示的方式對水瓶的水進行混合,得到樣品 A/B/C/D,取4只老鼠編號為 a/b/c/d 分別喝下對應的水,得到如下的表格:

        image.png

        在 24 小時候,統計老鼠的死亡情況,匯總后可以得到表格和結果:

        image.png

        答案呼之欲出,由于 8 瓶水可以兌出 4 份樣品,因此只需要 4 只老鼠即可在 24 小時后確定到底哪一瓶水是有毒的?;氐筋}目,如果是 1000 瓶水,只需要知道第 1000 號的二進制數?0b1111101000即可。該二進制數一共有 10 個比特位,意味著 1000 瓶水可以兌出 10 份樣品,也就是說只需要 10 只老鼠,就可以完成測試任務。

        尾聲

        關于位掩碼技術的探索就到這里。相信在認真讀完這篇文章以后,大家心里已經建立起對位掩碼技術的概念。這是一種非常特別的問題解決思路,也許在未來的某一天你真的會用上它。


        image.png

        查看原文

        贊 25 收藏 17 評論 0

        kruz 贊了文章 · 3月7日

        ?? 移動端 JS 引擎哪家強?美國硅谷找......

        如果你喜歡我的文章,希望點贊?? 收藏 ?? 評論 ?? 三連一下,謝謝你,這對我真的很重要!

        在一般的移動端開發場景中,每次更新應用功能都是通過 Native 語言開發并通過應用市場版本分發來實現的。但是市場瞬息萬變,Native 語言在開發效率上存在一定不足,并且從 APP 版本更新應用市場審核發布 再到 用戶下載更新,總會存在一定的時間差,這樣就導致新的功能無法及時覆蓋全量用戶。

        為了解決這個問題,開發者們一般會在項目里引入一門腳本語言,提速 APP 的研發流程。在移動端應用比較廣泛的腳本語言有 Lua 和 JavaScript,前者在游戲領域用的比較多,后者在應用領域用的比較多。本篇文章主要是想探討一下移動雙端(iOS & Android)的 JavaScript 引擎選型。由于個人水平有限,文章總會有遺漏和不足的地方,還請各位大佬多多指教。

        <!--truncate-->

        JS 引擎選型要點

        JavaScript 作為世界上最熱門的腳本語言,有著非常多的引擎實現:有 Apple 御用的 JavaScriptCore,有性能最強勁的 V8,還有最近熱度很高的 QuickJS......如何從這些 JS 引擎里選出最適合的?我個人認為要有幾個考量:

        • 性能:這個沒話說,肯定是越快越好
        • 體積:JS 引擎會增加一定的包體積
        • 內存占用:內存占用越少越好
        • JavaScript 語法支持程度:支持的新語法越多越好
        • 調試的便捷性:是否直接支持 debug?還是需要自己編譯實現調試工具鏈
        • 應用市場平臺規范:主要是 iOS 平臺,平臺禁止應用集成帶 JIT 功能的虛擬機

        比較麻煩的是,上面的幾個點都不是互相獨立的,比如說開啟 JIT 的 V8 引擎,性能肯定是最好的,但它引擎體積就很大,內存占用也很高;在包體積上很占優勢的 QuickJS,由于沒有 JIT 加持,和有 JIT 的引擎比起來平均會有 5-10 倍的性能差距。

        下面我會綜合剛剛提到的幾個點,并選擇了 JavaScriptCore,V8,HermesQuickJS 這 4 個 JSVM,說說它們的優點和特點,再談談他們的不足。

        JS 引擎功能大比拼

        1.JavaScriptCore

        mobile_JSVM_JSC


        JavaScriptCore 是 WebKit 默認的內嵌 JS 引擎,wikipedia 上都沒有獨立的詞條,只在 WebKit 詞條的三級目錄里介紹了一下,個人感覺還是有些不像話,畢竟也是老牌 JS 引擎了。

        由于 WebKit 是 Apple 率先開源的,所以 WebKit 引擎運用在 Apple 自家的 Safari 瀏覽器和 WebView 上,尤其是 iOS 系統上,因為 Apple 的限制,所有的網頁只能用 WebKit 加載,所以 WebKit 在 iOS 上達到了事實壟斷,作為 WebKit 模塊一部分的 JSC,順著政策春風,也「基本」壟斷了 iOS 平臺的 JS 引擎份額。

        壟斷歸壟斷,其實 JSC 的性能還是可以的,很多人不知道 JSC 的 JIT 功能其實比 V8 還要早,放在十幾年前是最好的 JS 引擎,只不過后來被 V8 追了上來。而且 JSC 有個重大利好,在 iOS7 之后,JSC 作為一個系統級的 Framework 開放給開發者使用,也就是說,如果你的 APP 使用 JSC,只需要在項目里 import 一下,包體積是 0 開銷的!這點在今天討論的 JS 引擎中,JSC 是最能打的。


        雖然開啟 JIT 的 JSC 性能很好,但是只限于蘋果御用的 Safari 瀏覽器和 WKWebView,只有這兩個地方 JIT 功能才是默認開啟的,如果在項目里直接引入 JSC,JIT 功能是關閉的。為什么這么做呢?RednaxelaFX 大佬 給出過非常專業的解釋

        JIT 編譯需要底層系統支持動態代碼生成,對操作系統來說這意味著要支持動態分配帶有“可寫可執行”權限的內存頁。當一個應用程序擁有請求分配可寫可執行內存頁的權限時,它會比較容易受到攻擊從而允許任意代碼動態生成并執行,這樣就讓惡意代碼更容易有機可乘。

        Apple 出于安全上的考慮,禁止了第三方 APP 使用 JSC 時開啟 JIT,這些特點在 React Native 的 JS Runtime 頁面也有過相關的解釋。不過在實際應用中,不做重 CPU 的運算只當膠水語言使用,JSC 還是綽綽有余了。


        上面的討論都是針對 iOS 系統的,在 Android 系統上,JSC 的表現就不盡人意了。JSC 并沒有對 Android 機型做很好的適配,雖然可以開啟 JIT,但是性能表現并不好,這也是 Facebook 決心制作 Hermes 的一個原因,具體的性能對比分析可見本文的 Hermes 小節。


        最后再說說 JSC 的調試支持情況。如果是 iOS 平臺,我們可以直接用 Safari 的 debbuger 功能調試,如果是 Android 平臺,目前我還沒有找到一個很好的真機調試方法。


        綜合來看,JavaScriptCore 在 iOS 平臺上有非常明顯的主場優勢,各個指標都是很優秀的,但在 Android 上因為缺乏優化,表現并不是很好。

        2.V8

        mobile_JSVM_V8


        V8,我想我不用過多解釋了,JavaScript 能有如今的地位,V8 功不可沒。性能沒得說,開啟 JIT 后就是業內最強(不止是 JS),有很多介紹 V8 的文章,我這里就不多描述了,我們這里說說 V8 在移動端的表現。


        同樣作為 Google 家的產品,每一臺 Android 手機上都安裝了基于 Chromium 的 WebView,V8 也一并捆綁了。但是 V8 和 Chromium 捆綁的太緊密了,不像 iOS 上的 JavaScriptCore 封裝為系統庫可以被所有 App 調用。這就導致你想在 Android 上用 V8 還得自己封裝,社區比較出名的項目是 J2V8,提供了 V8 的 Java bindings 案例。

        V8 性能沒得說,Android 上可以開啟 JIT,但這些優勢都是有代價的:開啟 JIT 后內存占用高,并且 V8 的包體積也不小(大概 7 MB 左右),如果作為只是畫 UI 的 Hybrid 系統,還是有些奢侈了。

        我們再說說 V8 在 iOS 上的集成。V8 在 2019 年推出了 JIT-less V8,也就是關閉 JIT 只使用 Ignition interpreter 解釋執行 JS 文件,那么我們在 iOS 上集成 V8 就成了可能,因為 Apple 還是支持接入只有解釋器功能的虛擬機引擎的。但是個人認為關閉了 JIT 的 V8 接入 iOS 價值不大,因為只開啟解釋器的話,這時候的 V8 和 JSC 的性能其實是差不多的,引入反而會增加一定的體積開銷。


        V8 還有一個有意思的特性很少人提及,那就是——堆快照(Heap snapshots),這個是 V8 在 2015 年就支持的功能,但是社區里很少有人討論它。

        堆快照是什么原理呢?一般來說 JSVM 啟動后,第一步往往是解析 JS 文件,這個還是比較耗時的,V8 支持預先生成 Heap snapshots,然后直接加載到堆內存中,快速的獲得 JS 的初始化上下文??缙脚_框架 NativeScript 就利用了這樣的技術,可以讓 JS 的加載速度提升 3 倍,技術細節可以看他們的博文。

        V8_heap_snapshots

        V8 真機調試也需要引入第三方庫,Android 端社區上有人對 J2V8 做了 Chrome 調試協議的擴展,即 J2V8-Debugger 項目,iOS 我沒有找到相關的項目,可能需要自己實現一套擴展。


        綜合來看 V8 的確是 JSVM 中的性能王者,Android 端使用時可以完全發揮它的威力,但是 iOS 平臺因為主場劣勢,并不是很推薦。

        3.Hermes

        mobile_JSVM_hermes


        Hermes 是 FaceBook 2019 年中旬開源的一款 JS 引擎,從 release 記錄可以看出,這個是專為 React Native 打造的 JS 引擎,可以說從設計之初就是為 Hybrid UI 系統打造。

        Hermes 一開始推出就是要替代原來 RN Android 端的 JS 引擎,即 JavaScriptCore(因為 JSC 在 Android 端表現太拉垮了)。我們可以理一下時間線,FaceBook 自從 2019-07-12 宣布 Hermes 開源后,jsc-android 的維護信息就永遠的停在了 2019-06-25,這個信號暗示得非常的明顯:JavaScriptCore Android 我們不再維護啦,大家都去用我們做的 Hermes 啊。

        最近 Hermes 已經計劃伴隨 React Native 0.64 版本登錄 iOS 平臺了,但是 RN 版本更新 blog 還沒有出,大家可以看看我之前對 Apple 開發者協議的解讀:Apple Agreement 3.3.2 規范解讀,在這里我就不多說了。


        Hermes 的特點主要是兩個,一個是不支持 JIT,一個是支持直接生成/加載字節碼,我們在下面分開講一下。

        Hermes 不支持 JIT 的主要原因有兩個:加入 JIT 后,JS 引擎啟動的預熱時間會變長,一定程度上會加長首屏 TTI(頁面首次加載可交互時間),現在的前端頁面都講究一個秒開,TTI 還是個挺重要的測量指標。另一個問題上 JIT 會增加包體積和內存占用,Chrome 內存占用高 V8 還是要承擔一定責任的。

        因為不支持 JIT,Hermes 在一些 CPU 密集計算的領域就不占優勢了,所以在 Hybrid 系統里,最優的解決方案就是充分發揮 JavaScript 膠水語言的作用,CPU 密集的計算(例如矩陣變換,參數加密等)放在 Native 里做,算好了再傳遞給 JS 表現在 UI 上,這樣可以兼顧性能和開發效率。


        Hermes 最引人矚目的就是支持生成字節碼了,我在之前的博文《?? 跨端框架的核心技術到底是什么?》也提到過,Hermes 加入 AOT 后,Babel、Minify、ParseCompile 這些流程全部都在開發者電腦上完成,直接下發字節碼讓 Hermes 運行就行,我們直接用個 demo 演示一下。

        Hermes

        先寫個 test.js 的文件,里面隨便寫點啥都行;然后編譯一下 Hermes 的源碼,編譯過程直接按文檔來就行,我這里就略過了。

        首先 Hermes 支持直接解釋運行 JS 代碼,就是正常的 JS 加載編譯運行流程。

        hermes test.js

        我們可以加入 -emit-binary 參數嘗試一下生成 Bytecode 的功能:

        hermes -emit-binary -out test.hbc test.js

        然后就會生成一份 test.hbc 字節碼文件:

        hermes_bytecode

        最后我們可以讓 Hermes 直接加載運行 test.hbc 文件:

        hermes test.hbc

        客觀評價一下 Hermes 的字節碼,首先省去了在 JS 引擎里解析編譯的流程,JS 代碼的加載速度將會大大加快,體現在 UI 上就是 TTI 時間會明顯縮短;另一個優勢 Hermes 的字節碼在設計時就考慮了移動端的性能限制,支持增量加載而不是全量加載,對內存受限的中低端 Android 機更友好;不過字節碼的體積會比原來的 JS 文件會大一些,但是考慮到 Hermes 引擎本身體積就不大,綜合考慮下來這些體積增量還是可以接受的。


        關于詳細的 Hermes 性能測試情況,網上有兩篇文章寫的比較好:一篇是 React Native Memory profiling: JSC vs V8 vs Hermes,可以看到在 Android 設備上 Hermes 的表現還是很優異的,而 JSC 的表現非常拉垮:

        JSCvsV8vsHermes

        另一篇是攜程的文章:攜程對 RN 新一代 JS 引擎 Hermes 的調研,可以看出 Hermes 綜合成績最高(JSC 還是一樣的拉垮):

        JSVM_CPU_Performance


        說完性能我們再說說 Hermes 的 JS 語法支持情況。Hermes 主要支持的是 ES6 語法,剛開源時不支持 Proxy,不過 v0.7.0 已經支持了。他們的團隊也比較有想法,不支持 witheval() 等這種屬于設計糟粕的 API,這種設計的權衡我個人還是比較認同的。


        最后我們談談 Hermes 的調試功能。目前 Hermes 已經支持了 Chrome 的調試協議,我們可以直接用 Chrome 的 debugging 工具直接調試 Hermes 引擎,具體的操作可見文檔:Debugging JS on Hermes using Google Chrome's DevTools


        綜合來看,Hermes 是一款專為移動端 Hybrid UI System 打造的 JS 引擎,如果要自建一套 Hybrid 系統,Hermes 是一個非常好的選擇。

        4.QuickJS

        mobile_JSVM_quickjs


        正式介紹 QuickJS 前我們先說說它的作者:Fabrice Bellard。

        軟件界一直有個說法,一個高級程序員創造的價值可以超過 20 個平庸的程序員,但 Fabrice Bellard 不是高級程序員,他是天才,在我看來他的創造力可以超過 20 個高級程序員,我們可以順著時間軸理一下他創造過些什么:

        • 1997年,發布了最快速的計算圓周率的算法,此算法是 Bailey-Borwein-Plouffe 公式的變體,前者的時間復雜度是O(n^3),他給優化成了O(n^2),使得計算速度提高了43%,這是他在數學上的成就
        • 2000 年,發布了 FFmpeg,這是他在音視頻領域的一個成就
        • 2000,2001,2018 三年三度獲得國際混淆 C 代碼大賽
        • 2002 年,發布了TinyGL,這是他在圖形學領域的成就
        • 2005 年,發布了 QEMU,這是他在虛擬化領域的成就
        • 2011 年,他用 JavaScript 寫了一個 PC 虛擬機 Jslinux,一個跑在瀏覽器上的 Linux 操作系統
        • 2019 年,發布了 QuickJS,一個支持 ES2020 規范的 JS 虛擬機

        當人和人之間的差距差了幾個數量級后,羨慕嫉妒之類的情緒就會轉變為崇拜了,Bellard 就是一個這樣的人。


        收復一下心情,我們來看一下 QuickJS 這個項目。QuickJS 繼承了 Fabrice Bellard 作品的一貫特色——小巧而又強大。

        QuickJS 體積非常小,只有幾個 C 文件,沒有亂七八糟的第三方依賴。但是他的功能又非常完善,JS 語法支持ES2020,Test262 的測試顯示,QuickJS 的語法支持度比 V8 還要高。

        test262


        那么 QuickJS 的性能如何呢?QuickJS 官上有個基準測試,綜合比較了多款 JS 引擎對同一測試用例的跑分情況。下面是測試結果:

        JSVM_Benchmark

        結合上面的表格和個人的一些測試,可以簡單的得出一些結論:

        • 開啟 JIT 的 V8 綜合評分差不多是 QuickJS 的 35 倍,但是在同等主打輕量的 JS 引擎中,QuickJS 的性能還是很耀眼的
        • 在內存占用上,QuickJS 遠低于 V8,畢竟 JIT 是是吃內存的大戶,而且 QuickJS 的設計對嵌入式系統很友好(Bellard 成就獎杯 ?? 再 +1)
        • QuickJS 和 Hermes 的跑分情況是差不多的,我私下做了一些性能測試,這兩個引擎的表現也很相近


        因為 QuickJS 的設計,我不經好奇他和 Lua 的性能對比如何。Lua 是一門非常小巧精悍的語言,在游戲領域和 C/C++ 開發中一直充當膠水語言的作用,我個人寫了一些測試用例,發現 QuickJS 和 Lua 的執行效率也是差不多的,后來在網上找到一篇博文 Lua vs QuickJS,這個老哥也做了一些測試,結論也是它倆的性能差不多,在部分場景 Lua 會比 QuickJS 快一些。


        官方文檔里有提到,QuickJS 支持生成字節碼,這樣可以免去 JS 文件編譯解析的過程。我一開始以為 QuickJS 和 Hermes 一樣,可以直接生成字節碼,然后交給 QuickJS 解釋執行。后來自己編譯了一下才發現,QuickJS 的作用機制和 Hermes 還不太一樣:qjsc 生成字節碼的 -e-c 選項,都是先把 js 文件生成一份字節碼,然后拼到一個 .c 文件里,大概長下面的這個樣子:

        #include <quickjs/quickjs-libc.h>
        
        const uint32_t qjsc_hello_size = 87;
        
        // JS 文件編譯生成的字節碼都在這個數組里
        const uint8_t qjsc_hello[87] = {
         0x02, 0x04, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f,
         0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67, 0x16, 0x48,
         0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72,
         0x6c, 0x64, 0x22, 0x65, 0x78, 0x61, 0x6d, 0x70,
         0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c,
         0x6f, 0x2e, 0x6a, 0x73, 0x0e, 0x00, 0x06, 0x00,
         0x9e, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00,
         0x14, 0x01, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x39,
         0xf1, 0x00, 0x00, 0x00, 0x43, 0xf2, 0x00, 0x00,
         0x00, 0x04, 0xf3, 0x00, 0x00, 0x00, 0x24, 0x01,
         0x00, 0xd1, 0x28, 0xe8, 0x03, 0x01, 0x00,
        };
        
        int main(int argc, char **argv)
        {
          JSRuntime *rt;
          JSContext *ctx;
          rt = JS_NewRuntime();
          ctx = JS_NewContextRaw(rt);
          JS_AddIntrinsicBaseObjects(ctx);
          js_std_add_helpers(ctx, argc, argv);
          js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0);
          js_std_loop(ctx);
          JS_FreeContext(ctx);
          JS_FreeRuntime(rt);
          return 0;
        }

        因為這是個 .c 文件,想跑起來還得編譯一次生成二進制文件。

        從字節碼這個設計點來看,QuickJS 和 Hermes 的定位還是不太一樣的。雖然直接生成字節碼可以大大減少 JS 文本文件的解析時間,但是 QuickJS 還是更偏嵌入式一些,生成的字節碼放在一個 C 文件中,還需要進行編譯才能運行;Hermes 為 React Native 而生,生成的字節碼一開始就考慮到分發功能(熱更新就是一個應用場景),支持字節碼的直接加載運行,不需要再編譯一次。


        上面主要還是對性能的考量,下面我們看看開發體驗,首先是 QuickJS 的調試功能支持。到目前為止(2021-02-22),QuickJS 還沒有官方的調試器,也就是說 debugger 語句會被忽略,社區有人實現了一套基于 VSCode 的調試器支持 vscode-quickjs-debug,但是會對 QuickJS 做一些定制,個人還是蠻期待官方支持某個調試器協議的。

        集成 的角度上看,社區上已經有了 iOSAndroid 的示例項目,可以拿來用來參考接入到自己的工程中。


        綜合來看,QuickJS 是一款潛力非常大的 JS 引擎,在 JS 語法高度支持的前提下,還把性能和體積都優化到了極致。在移動端的 Hybrid UI 架構和游戲腳本系統都可以考慮接入。

        選型思路

        1.單引擎

        單引擎的意思就是 iOS 端和 Android 端統一采用一個引擎,這樣做的話在 JS 層差異可以抹平,不容易出現同一份 JS 代碼在 iOS 上運行是好的,Android 上就出錯的奇異 BUG。結合市面上的跨端方案,大概有下面三種選型:

        • 統一采用 JSC:這個是 React Native 0.60 之前的方案
        • 統一使用 Hermes:這個是 React Native 0.64 之后的設計方案
        • 統一采用 QuickJS:QuickJS 體積很小,可以用來制作非常輕量的 Hybrid 系統

        上面看出沒有統一采用 V8,這個就是我前面說的,V8 在 iOS 平臺沒有主場優勢,關閉 JIT 后性能和 JSC 差不多,還會增大包體積,并不是很劃算。

        2.雙引擎

        雙引擎也很好理解,就是 iOS 端和 Android 端各用各的,優點是可以發揮各自的主場優勢,缺點是可能會因為平臺不一致導致雙端運行結果不統一,現在的方案有這么幾種:

        • iOS 用 JSC,Android 用 V8:Weex,NativeScript 都是這樣的,可以在包體積和性能上有較好的均衡
        • iOS 用 JSC,Android 用 Hermes:React Natvie 現如今的方案
        • iOS 用 JSC,Android 用 QuickJS:滴滴的跨端框架 hummer 就是這樣的設計

        從選型上看,iOS 上都選擇了 JSC,Android 各有各的選擇,倒是充分發揮了兩個平臺的特色 : )

        3.調試

        無論是單引擎還是雙引擎,集成后的業務開發體驗也很重要。對于自帶 debugger 功能的引擎來說一切都不在話下,但是對于沒有實現調試協議的引擎來說,缺少 debugger 還是會影響體驗的。

        但不是也沒有辦法,一般來說我們可以曲線救國,類似于 React Native 的 Remote JS Debugging 的思路,我們可以加個開關,把 JS 代碼通過 websocket 傳送到 Chrome 的 Web Worker,然后用 Chrome 的 V8 進行調試。這樣做的優勢是可以調整一些業務上的 BUG,劣勢就是又會引入一個 JS 引擎,萬一遇到一些引擎實現的 BUG,就很難 debug 了。不過好在這種情況非常非常少見,我們也不能因噎廢食對吧。

        總結

        本文從性能、體積、調試便捷性等功能點出發,分析了 JavaScriptCore,V8,HermesQuickJS 這 4 款 JS 引擎,分別分析了它們的缺點和弱點,如果大家有移動端 JS 引擎選型的困惑,我認為從本文出發,還是可以給不少人以靈感的,希望我的這篇文章能幫助到大家。

        參考鏈接

        跨端框架的核心技術到底是什么?

        如何隱藏你的熱更新 bundle 文件?

        深入理解JSCore

        QuickJS 引擎一年見聞錄


        如果你喜歡我的文章,希望點贊?? 收藏 ?? 在看 ?? 三連一下,謝謝你,這對我真的很重要!

        歡迎大家關注我的微信公眾號:鹵蛋實驗室,目前專注前端技術,對圖形學也有一些微小研究。

        原文鏈接 ?? ?? 移動端 JS 引擎哪家強?美國硅谷找......:更新更及時,閱讀體驗更佳

        查看原文

        贊 13 收藏 7 評論 0

        kruz 收藏了文章 · 2020-03-19

        預測最近面試會考 Cookie 的 SameSite 屬性

        前言

        2 月份發布的 Chrome 80 版本中默認屏蔽了第三方的 Cookie,在灰度期間,就導致了阿里系的很多應用都產生了問題,為此還專門成立了小組,推動各 BU 進行改造,目前阿里系基本已經改造完成。所有的前端團隊估計都收到過通知,也著實加深了一把大家對于 Cookie 的理解,所以很可能就此出個面試題,而即便不是面試題,當問到 HTTP 相關內容的時候,不妨也扯到這件事情來,一能表明你對前端時事的跟進,二還能借此引申到前端安全方面的內容,為你的面試加分。

        所以本文就給大家介紹一下瀏覽器的 Cookie 以及這個"火熱"的 SameSite 屬性。

        HTTP

        一般我們都會說 “HTTP 是一個無狀態的協議”,不過要注意這里的 HTTP 其實是指 HTTP 1.x,而所謂無狀態協議,簡單的理解就是即使同一個客戶端連續兩次發送請求給服務器,服務器也識別不出這是同一個客戶端發送的請求,這導致的問題就比如你加了一個商品到購物車中,但因為識別不出是同一個客戶端,你刷新下頁面就沒有了……

        Cookie

        為了解決 HTTP 無狀態導致的問題,后來出現了 Cookie。不過這樣說可能會讓你產生一些誤解,首先無狀態并不是不好,有優點,但也會導致一些問題。而 Cookie 的存在也不是為了解決通訊協議無狀態的問題,只是為了解決客戶端與服務端會話狀態的問題,這個狀態是指后端服務的狀態而非通訊協議的狀態。

        Cookie 介紹

        那我們來看下 Cookie,引用下維基百科:

        Cookie(復數形態Cookies),類型為「小型文本文件」,指某些網站為了辨別用戶身份而儲存在用戶本地終端上的數據。

        作為一段一般不超過 4KB 的小型文本數據,它由一個名稱(Name)、一個值(Value)和其它幾個用于控制 Cookie 有效期、安全性、使用范圍的可選屬性組成,這些涉及的屬性我們會在后面會介紹。

        Cookie 的查看

        我們可以在瀏覽器的開發者工具中查看到當前頁面的 Cookie:

        盡管我們在瀏覽器里查看到了 Cookie,這并不意味著 Cookie 文件只是存放在瀏覽器里的。實際上,Cookies 相關的內容還可以存在本地文件里,就比如說 Mac 下的 Chrome,存放目錄就是~/Library/Application Support/Google/Chrome/Default,里面會有一個名為 Cookies 的數據庫文件,你可以使用 sqlite 軟件打開它:

        存放在本地的好處就在于即使你關閉了瀏覽器,Cookie 依然可以生效。

        Cookie 的設置

        那 Cookie 是怎么設置的呢?簡單來說就是

        1. 客戶端發送 HTTP 請求到服務器
        2. 當服務器收到 HTTP 請求時,在響應頭里面添加一個 Set-Cookie 字段
        3. 瀏覽器收到響應后保存下 Cookie
        4. 之后對該服務器每一次請求中都通過 Cookie 字段將 Cookie 信息發送給服務器。

        我們以https://main.m.taobao.com/為例來看下這個過程:

        我們在請求返回的 Response Headers 可以看到 Set-Cookie 字段:

        然后我們查看下 Cookie:

        我們刷新一遍頁面,再看下這個請求,可以在 Request Headers 看到 cookie 字段:

        Cookies 的屬性

        在下面這張圖里我們可以看到 Cookies 相關的一些屬性:

        這里主要說一些大家可能沒有注意的點:

        Name/Value

        用 JavaScript 操作 Cookie 的時候注意對 Value 進行編碼處理。

        Expires

        Expires 用于設置 Cookie 的過期時間。比如:

        Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
        

        當 Expires 屬性缺省時,表示是會話性 Cookie,像上圖 Expires 的值為 Session,表示的就是會話性 Cookie。當為會話性 Cookie 的時候,值保存在客戶端內存中,并在用戶關閉瀏覽器時失效。需要注意的是,有些瀏覽器提供了會話恢復功能,這種情況下即使關閉了瀏覽器,會話期 Cookie 也會被保留下來,就好像瀏覽器從來沒有關閉一樣。

        與會話性 Cookie 相對的是持久性 Cookie,持久性 Cookies 會保存在用戶的硬盤中,直至過期或者清除 Cookie。這里值得注意的是,設定的日期和時間只與客戶端相關,而不是服務端。

        Max-Age

        Max-Age 用于設置在 Cookie 失效之前需要經過的秒數。比如:

        Set-Cookie: id=a3fWa; Max-Age=604800;
        

        Max-Age 可以為正數、負數、甚至是 0。

        如果 max-Age 屬性為正數時,瀏覽器會將其持久化,即寫到對應的 Cookie 文件中。

        當 max-Age 屬性為負數,則表示該 Cookie 只是一個會話性 Cookie。

        當 max-Age 為 0 時,則會立即刪除這個 Cookie。

        假如 Expires 和 Max-Age 都存在,Max-Age 優先級更高。

        Domain

        Domain 指定了 Cookie 可以送達的主機名。假如沒有指定,那么默認值為當前文檔訪問地址中的主機部分(但是不包含子域名)。

        像淘寶首頁設置的 Domain 就是 .taobao.com,這樣無論是a.taobao.com還是b.taobao.com都可以使用 Cookie。

        在這里注意的是,不能跨域設置 Cookie,比如阿里域名下的頁面把 Domain 設置成百度是無效的:

        Set-Cookie: qwerty=219ffwef9w0f; Domain=baidu.com; Path=/; Expires=Wed, 30 Aug 2020 00:00:00 GMT

        Path

        Path 指定了一個 URL 路徑,這個路徑必須出現在要請求的資源的路徑中才可以發送 Cookie 首部。比如設置Path=/docs,/docs/Web/下的資源會帶 Cookie 首部,/test則不會攜帶 Cookie 首部。

        Domain 和 Path 標識共同定義了 Cookie 的作用域:即 Cookie 應該發送給哪些 URL。

        Secure屬性

        標記為 Secure 的 Cookie 只應通過被HTTPS協議加密過的請求發送給服務端。使用 HTTPS 安全協議,可以保護 Cookie 在瀏覽器和 Web 服務器間的傳輸過程中不被竊取和篡改。

        HTTPOnly

        設置 HTTPOnly 屬性可以防止客戶端腳本通過 document.cookie 等方式訪問 Cookie,有助于避免 XSS 攻擊。

        SameSite

        SameSite 是最近非常值得一提的內容,因為 2 月份發布的 Chrome80 版本中默認屏蔽了第三方的 Cookie,這會導致阿里系的很多應用都產生問題,為此還專門成立了問題小組,推動各 BU 進行改造。

        作用

        我們先來看看這個屬性的作用:

        SameSite 屬性可以讓 Cookie 在跨站請求時不會被發送,從而可以阻止跨站請求偽造攻擊(CSRF)。

        屬性值

        SameSite 可以有下面三種值:

        1. Strict僅允許一方請求攜帶 Cookie,即瀏覽器將只發送相同站點請求的 Cookie,即當前網頁 URL 與請求目標 URL 完全一致。
        2. Lax允許部分第三方請求攜帶 Cookie
        3. None無論是否跨站都會發送 Cookie

        之前默認是 None 的,Chrome80 后默認是 Lax。

        跨域和跨站

        首先要理解的一點就是跨站和跨域是不同的。同站(same-site)/跨站(cross-site)」和第一方(first-party)/第三方(third-party)是等價的。但是與瀏覽器同源策略(SOP)中的「同源(same-origin)/跨域(cross-origin)」是完全不同的概念。

        同源策略的同源是指兩個 URL 的協議/主機名/端口一致。例如,https://www.taobao.com/pages/...,它的協議是 https,主機名是www.taobao.com,端口是 443。

        同源策略作為瀏覽器的安全基石,其「同源」判斷是比較嚴格的,相對而言,Cookie中的「同站」判斷就比較寬松:只要兩個 URL 的 eTLD+1 相同即可,不需要考慮協議和端口。其中,eTLD 表示有效頂級域名,注冊于 Mozilla 維護的公共后綴列表(Public Suffix List)中,例如,.com、.co.uk、.github.io 等。eTLD+1 則表示,有效頂級域名+二級域名,例如taobao.com等。

        舉幾個例子,www.taobao.comwww.baidu.com是跨站,www.a.taobao.comwww.b.taobao.com是同站,a.github.iob.github.io是跨站(注意是跨站)。

        改變

        接下來看下從 None 改成 Lax 到底影響了哪些地方的 Cookies 的發送?直接來一個圖表:

        從上圖可以看出,對大部分 web 應用而言,Post 表單,iframe,AJAX,Image 這四種情況從以前的跨站會發送三方 Cookie,變成了不發送。

        Post表單:應該的,學 CSRF 總會舉表單的例子。

        iframe:iframe 嵌入的 web 應用有很多是跨站的,都會受到影響。

        AJAX:可能會影響部分前端取值的行為和結果。

        Image:圖片一般放 CDN,大部分情況不需要 Cookie,故影響有限。但如果引用了需要鑒權的圖片,可能會受到影響。

        除了這些還有 script 的方式,這種方式也不會發送 Cookie,像淘寶的大部分請求都是 jsonp,如果涉及到跨站也有可能會被影響。

        問題

        我們再看看會出現什么的問題?舉幾個例子:

        1. 天貓和飛豬的頁面靠請求淘寶域名下的接口獲取登錄信息,由于 Cookie 丟失,用戶無法登錄,頁面還會誤判斷成是由于用戶開啟了瀏覽器的“禁止第三方 Cookie”功能導致而給與錯誤的提示
        2. 淘寶部分頁面內嵌支付寶確認付款和確認收貨頁面、天貓內嵌淘寶的登錄頁面等,由于 Cookie 失效,付款、登錄等操作都會失敗
        3. 阿里媽媽在各大網站比如今日頭條,網易,微博等投放的廣告,也是用 iframe 嵌入的,沒有了 Cookie,就不能準確的進行推薦
        4. 一些埋點系統會把用戶 id 信息埋到 Cookie 中,用于日志上報,這種系統一般走的都是單獨的域名,與業務域名分開,所以也會受到影響。
        5. 一些用于防止惡意請求的系統,對判斷為惡意請求的訪問會彈出驗證碼讓用戶進行安全驗證,通過安全驗證后會在請求所在域種一個Cookie,請求中帶上這個Cookie之后,短時間內不再彈安全驗證碼。在Chrome80以上如果因為Samesite的原因請求沒辦法帶上這個Cookie,則會出現一直彈出驗證碼進行安全驗證。
        6. 天貓商家后臺請求了跨域的接口,因為沒有 Cookie,接口不會返回數據
        7. ……

        如果不解決,影響的系統其實還是很多的……

        解決

        解決方案就是設置 SameSite 為 none。

        以 Adobe 網站為例:https://www.adobe.com/sea/,查看請求可以看到:

        不過也會有兩點要注意的地方:

        1. HTTP 接口不支持 SameSite=none

        如果你想加 SameSite=none 屬性,那么該 Cookie 就必須同時加上 Secure 屬性,表示只有在 HTTPS 協議下該 Cookie 才會被發送。

        1. 需要 UA 檢測,部分瀏覽器不能加 SameSite=none

        IOS 12 的 Safari 以及老版本的一些 Chrome 會把 SameSite=none 識別成 SameSite=Strict,所以服務端必須在下發 Set-Cookie 響應頭時進行 User-Agent 檢測,對這些瀏覽器不下發 SameSite=none 屬性

        Cookie 的作用

        Cookie 主要用于以下三個方面:

        1. 會話狀態管理(如用戶登錄狀態、購物車、游戲分數或其它需要記錄的信息)
        2. 個性化設置(如用戶自定義設置、主題等)
        3. 瀏覽器行為跟蹤(如跟蹤分析用戶行為等)

        Cookie 的缺點

        如果被問到話,可以從大小、安全、增加請求大小等方面回答。

        參考

        1. MDN
        2. HTTP是一個無狀態的協議。這句話里的無狀態是什么意思? - 靈劍的回答 - 知乎
        3. Chrome 80.0中將SameSite的默認值設為Lax,對現有的Cookie使用有什么影響? - 紫云飛的回答 - 知乎
        4. 一些內部文章

        各種系列

        各種系列文章目錄地址:https://github.com/mqyqingfeng/Blog

        如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果喜歡或者 有所啟發,歡迎 star,對作者也是一種鼓勵。

        再其他

        建立了一個「前端校招面試沖刺互助群」,歡迎加「taoxiaozhao233」 入群~

        查看原文

        kruz 贊了文章 · 2020-03-14

        【整理】前端優化得有個好手段,比如看這個清單??????????

        前端優化指南

        一名合格的Web前端工程師,Web前端性能優化是一個必須要掌握的知識。 大部分都是規規矩矩寫好代碼,設計模式好并項目好管理。
        而且在HTTP請求和代碼耗時間的地方著手。

        • 頁面級別的優化,比如減少 Http 請求次數、加快資源的加載速度;
        • 代碼級別的優化,頁面重新渲染一次會經過瀏覽器的重排(reflow)和重繪(repaint),這兩部操作是非常耗時的

        而網頁性能優化,緩存優化、加載時優化、動畫優化呢?
        所以我們才對瀏覽器下手,了解它的緩存機制。

        可參考的書籍??:★《高性能網站建設指南》★《HTTP權威指南》★《Web性能實踐日志》★《你不知道的JavaScript》★《方寸有度:百度移動用戶體驗設計之道》★《全棧應用開發:精益實踐》★《漸進增強:跨平臺用戶體驗設計》★《前端工程化:體系設計與實踐》★《前端進階之路:前端架構設計》★《高效前端:Web高效編程與優化實踐》★《NODEJS硬實戰筆記》
        甚至☆《學會提問》☆《刻意練習》☆《代碼整潔之道》
        ?`?.??.?′??????????
        看看哪些適合你,又有哪些可以參考的。

        吾觀自古賢達人,功成不退皆殞身

        東風不與周郎便,銅雀春深鎖二喬

        我寄愁心與明月,隨風直到夜郎西

        故人西辭黃鶴樓,煙花三月下揚州

        金樽清酒斗十千,玉盤珍羞直萬錢

        參考

        想了解更多,點擊【??Find the latest breaking √vue3 & vue-cli 3+ News.

        ?????Cool Friends?????
        Thanks?(?ω?)?

        image.png

        查看原文

        贊 110 收藏 85 評論 1

        kruz 關注了專欄 · 2020-03-05

        一個前端菜鳥的成長史

        前端知識積累

        關注 96

        kruz 贊了文章 · 2020-03-05

        人人都能懂的Vue源碼系列—01—Vue源碼目錄結構

        閱讀Vue的源碼,或者說閱讀一個框架的源碼,了解它的目錄結構都是很有幫助的。下面我們來看看Vue源碼的目錄結構。
        vue源碼目錄結構

        Vue各目錄簡介

        下圖是Vue各個目錄的功能介紹

        Vue源碼目錄結構詳細
        上圖就是關于Vue源碼整體目錄結構的介紹了,我們熟悉每個模塊具體的功能之后,對我們之后繼續研究源碼是很有幫助的。下次談論的主題是Vue的構造函數,當new Vue實例的時候,會發生什么呢?生成的Vue實例又有哪些屬性和方法呢?我們下篇文章會進行詳細的說明。
        人人都能懂的Vue源碼系列文章將會詳細的介紹Vue源碼的方方面面。為了讓初學者也能讀懂,盡量把知識點分割的很小。希望大家耐心等待更新,如果對文章內容有疑問或者質疑,歡迎在評論區進行討論。

        參考資料

        1. Flow類型檢查
        2. Typescript類型檢查
        3. Snabbdom
        4. Vue-server-renderer
        5. weex-vue-framework
        查看原文

        贊 43 收藏 46 評論 4

        kruz 收藏了文章 · 2020-03-01

        阿里等大廠的研發流程,進去前先了解一下

        本文 GitHubhttps://github.com/JavaFamily 已收錄,有一線大廠面試完整考點和系列文章。

        前言

        我的讀者好像學生居多,然后大家最近問的比較多的一個話題就是大廠的研發流程,都比較好奇,整個流程是怎么操作的。

        我也不多BB了,那下面就跟隨暖男的腳步,走進大廠研發流程吧。

        正文

        我們先看看一個產品有哪些研發流程,帥丙就用自己接觸的阿里系的研發流程舉例了,這也基本上是互聯網大廠的研發流程了,可能細節有出入,但是絕對大同小異。

        我問了下字節,多多,騰訊的朋友出入不大,所以還是具有代表性。

        看完流程我們就一個個點的去看看每個環節干了些啥,我們開發同學在這個環節需要做啥,以及在每個環節的職能。

        需求提出:

        這個環節主要是產品爸爸給我們提需求,每個需求都是他們從用戶,或者自己絞盡腦汁想出來的,但是產品爸爸還拿不準,不能直接敲定,所以就需要我們大家(產品,UI,前端,后端,客戶端和測試)一起討論一下,看看這個需求是否合理,或者這個需求是否有意義,能否達到預期,技術實現的成本,周期等等。

        一旦聊成了,他們就會進入下一個階段,聊不成他會想方設法讓你答應,然后進入下個階段,知道我為啥叫產品爸爸了吧?

        需求PRD提出:

        這個階段,產品爸爸會根據第一版聊下來的結果,大致出一個Demo版本的PRD,會畫出初版的原型圖,并且配上文字說明,所有涉及到的業務,還有交互細節都會羅列出來。

        大致就是下圖這樣:

        這個時候大家又會圍繞這一版本去開會討論,敲定細節,這個環節會久點,因為細節比較認真,邏輯也不能出錯,還有UI稿子也得敲定,這里如果不敲定邏輯,UI提前去畫原型圖,后面假如邏輯推翻,一切重來就會浪費大量時間。

        這一環節大家都會把細節問清楚,不了解的點也會去了解,測試,開發,UI我們都會在會議上提出自己的觀點,自己的意見,然后等產品反饋,最后意見一致之后,產品當天就回改出敲定版本。

        UI就會按照產品爸爸的意思去作圖,接下來就是交互設計評審了。

        交互設計評審:

        UI會畫出客戶端,前端,H5開發所需要的UI圖,基本上就是我們看到的產品的樣子了,不過還是要敲定細節,比如按鈕合理不,或者上面數據是否在這展示,或者這里展示的數據是否合理。

        這個環節會比較快,只要UI按照之前敲定的邏輯開發,出入不會很大,一般都是小改。

        但是也不乏很多,之前敲定了情況,等UI按照敲定版本出了圖,但是卻發現出圖之后有些不合理的點,比如是否應該在這里展示GMV(銷售總額),或者是否這樣展示活動規則啥的,會有這種情況,不過是小概率事件,改動也不會特別大。

        UI界面:

        大家看到的這種操作界面,按鈕,圖標的各種位置和圖案,都是UI在這個階段設計好的。(我什么都沒暗示,不用關注我的B站

        大家敲定后就進入我們開發人員的回合了。

        概要設計:

        概要設計,這個是大廠程序員需求下來之后基本上都會做的一步,不過看需求大小,可能很多小需求直接就詳細設計了,也有啥設計都不用做的小改動,具體需求具體分析嘛。

        很多不了解的同學可能會問,需要設計什么呢?為什么要設計呢?

        問得好,經??次椅恼碌亩贾?,技術是把雙刃劍,你用了技術之后你是不是需要列出他的優點缺點,出問題之后的解決方案,還有可能出現的問題,注意點等等。

        這么是為了讓你能有把控力,比如你這個需求接入了新技術EsElasticsearch)你什么都不管你就是要接入它,你把他開發好了上線了,但是有啥坑你知道么?上線崩了怎么辦?

        不主動,不拒絕,不負責,這是渣男的行徑,我們需要負起責任。

        這個環節你需要考慮這個需求涉及到哪些服務了,需要新增哪些接口,修改哪些接口,表有現場的還是要新建表,字段要新建么?

        其實遠遠不止這些問題,這就是我們做設計的主要原因,也是大家工作里面能成長的途徑之一,你以為大佬們的經驗是怎么來的?

        推薦工具:Xmind/ProcessOn

        ProcessOn是我使用最頻繁的工具了,我身邊也有很多小伙伴在用,也推薦大家都使用:

        大家在學習,看書等等的時候做個腦圖,后面學習和復習的時候思路會很清晰,而且效率瞬間很多,形成知識體系。

        概要設計一般就是做個大概,給大家看一下我自己在設計ES相關的需求的時候的概設,比較粗糙看個大概就好了:

        這個設計好了,就需要給Leader看,看理解程度,一兩次返工是有可能的,如果你像或者像敖丙一樣笨的話,是有可能會被打回N次的,這里我得提一下,好好做設計好處大大的有,自己體會。

        然后會進行一輪測試用例評審,比如你涉及哪些服務,新增了哪些接口,改了哪些接口,都是要同步出來的,至于為啥?

        是因為測試會依據這個數據,評估影響范圍,方便他寫測試用例,后面會提到。

        詳細設計

        小伙伴又要問了啥是詳細設計呀帥丙?

        傻瓜,簡單呀,見名知意嘛,概要設計是大概的設計,詳細設計是詳細的設計。

        我們研發的時候整個流程往往很復雜,如果你理解不對直接就寫代碼,最后容易造成返工,延期,加班,被罵,心情差,回家吵架,離家出走,露宿街頭,饑寒交迫,被迫吃野味,然后全國。。。。

        看到不做詳細設計的后果了吧,其實大家花點時間做詳細設計很有必要,你思路完全清晰了,寫代碼那就是分分鐘的事情,不是嘛?

        那再看看帥丙的一個小設計吧,之前文章中大量的流程圖,時序圖都來自它,主要是這玩意還是在線的,都不用下載很方便啊。

        詳細設計的工具我用的就是之前提到的在線作圖神器:ProcessOn https://www.processon.com

        還是我自己之前設計的一些流程圖,大家可以看看:

        這個環節一樣重要,這個地方如果你能想好很多細節,開發的時候效率會高很多,像我上面的一些點,基本上就是看著圖開發了。

        這個環節一般上不需要Leader參與,但是如果你有疑問或者不了解的點還是要提出來的。

        測試用例評審:

        上面我們說過,測試會根據你的概要設計,評估你的影響范圍,你的影響點,新增和改動的接口啥的,去編寫自己的測試用例。

        測試用例,主要是為了把改動點影響點都考慮到,測全一點,免得上線了影響別的現有業務,也是為了把你開發的功能可能出現的bug給排除了。

        我拿個小破站的小用例大家看看,這個比較粗糙但是也有點那味了。

        這個環節也會開會討論,也是細節的確定,比如他寫的是否合理,或者有什么點沒考慮到,大家有沒有補充的。

        接口定義&開發&前后端聯調

        這個環節其實比較好理解,啥都敲定了,那就開發唄,開發差不多了,就得前后端聯調了。

        這里有個小細節還是想說一下,一般開發前我們都會提前定義數據類型,接口名稱,然后在公司的接口工具上給出鏈接和參數,方便前端爸爸mock數據。

        他總不能等我們后端開發完了,才去開發嘛,這樣效率打折扣,所以都是后端先定義好,然后前后端并行開發的。

        后端開發好,一般都是會發布到聯調環境,我們有哪些環境,聯調環境在我們所有的環境中處于哪個地位呢?

        大家可以看到我列出了我們開發的所有環境。

        Tip:日常環境不能由開發人員發布,是因為測試流程比較久,所以不能中斷,如果你一直發布會影響測試的效率,在發布期間他們是沒辦法干活的,而且很多部門涉及相同的服務,你發布還會影響別人。

        測試發布之前,在測試群里問問可以發某個服務么,大家覺得不影響,那么就可以發了,懂了吧。

        預發環境,也叫灰度環境,這是跟線上數據一樣的一個環境,只是只能內網訪問,一般這一步是防止很多是因為日常的數據量不夠真實,數據級別達不到線上的量級無法測出的bug。

        扯遠了,聯調完了就是代碼Review了。

        代碼Review:

        codeReview環節,畫一下重點,這可能是整個研發流程中,讓你成長最快的一個環節,讓組員和Leader Review你的代碼,往往他們能給你很多業務上和技術上的建議和意見。

        過來人的經驗你就說香不香吧,以前老大經常沒時間,但是我就是煩著他要Review,后來他說不用review了,但是我還是要組員大佬review,因為我很享受別人對我提建議的時候,這不就是成長,掃盲的好時機嘛。

        提測&灰度發布&產品第一次驗收

        這一階段就是把代碼都發到日常環境,然后等測試爸爸測試,這個環節開發同學如果沒BUG是比較輕松的,等著就好了,可以看看丙丙的文章啊,看看丙丙的B站視頻什么的。

        但是如果你BUG多,那我覺得你可能會生不如死,因為有的bug真的找很久很久的,調用鏈路又長,特別是跨服務又涉及消息隊列,或者第三方的接口什么的。

        img

        img

        總之你也不知道會出現什么bug,我看身邊的大神也只能用經驗避免常見的吭,孰能生巧吧。

        發布計劃

        敲黑板,這個確實是比較重要的環節,這個環節主要是開發同學和前端同學說好一個發布時間,然后制定一個發布計劃,為啥要發布計劃呢?

        我們開發一個需求,可能涉及到N個服務,這些服務是有依賴關系的,那就需要打包,比如訂單系統,依賴人員系統。優惠券系統,也依賴人員系統,然后訂單系統還依賴優惠券系統,是不是有點亂了?

        我們看圖:

        打包和發布順序原則上是一樣的,從沒完全依賴的服務按照順序發布到最后一個服務。

        生成環境上線:

        這就是神圣而莊嚴的上線環節,一般在這個環節丙丙都是要洗手洗澡,然后才點下那個神圣的發布按鈕。

        一般現在都是自動化發布,界面上點點就好了,記得丙丙大學發布都是進服務器一個個kill進程,替換jar包然后重啟。

        現在都是分布式的集群,這樣發無疑會累死,我之前負責的系統有50多臺機器,一般都是4臺4臺發布。

        日志觀察&產品第二次驗收

        一般發布第一批之后不會馬上發布第二批,而是觀察錯誤日志,看看是否正常,有時候會發現還是會出現異常情況的,那就保留錯誤日志,然后回滾。

        知道解決了再發布,順利的話就沒啥錯誤,一口氣發完了,看了下時間凌晨了,那發完差不多也得回家了。

        一次發布可能涉及服務多的話,真的有可能發布這么久,但是沒辦法,線上出問題就是掉腦袋的事情。

        日志觀察一般公司都有錯誤日志搜集系統,或者自己登錄跳板機查看就好了。

        沒問題,發完之后告訴產品大大就好了。

        需求結束

        至此基本上一個需求可能就結束了,其實還是很不容易的,短的需求幾天,長的需求幾個月,中間涂涂改改,BUG,技術難點都是你要面對的,不過沒啥大問題,我們技術人嘛皮實能頂。

        總結

        產品研發流程大家是不是覺得有點復雜,或者覺得很多點有點小題大做了,不瞞你說,剛開始我也這么認為的,但是隨著時間的推移,你會發現有時候越是這樣規范,越是提升了效率,也提升了產品質量。

        對自己設計的嚴苛也會讓你的業務能力提升,開發考慮的點也越來越廣泛,我想大佬應該都是這樣走過去的,那沒啥好說的,我們也走。

        最后給大家看看我自己搞的一個項目管理模板吧,基本上能適用大部分項目了,要xmind格式的公眾號回復【項目】即可。

        我是敖丙,一個在互聯網茍且偷生的程序員。

        創作不易,不想被白嫖,各位的「三連」就是丙丙創作的最大動力,我們下篇文章見!


        本文 GitHubhttps://github.com/JavaFamily 已經收錄,有大廠面試完整考點,歡迎Star。

        你知道的越多,你不知道的越多

        查看原文

        kruz 收藏了文章 · 2020-03-01

        重新認識caniuse

        困惑

        相信大家都曾用caniuse網站查詢過css、js的一些兼容性問題,并且都從它反饋的兼容性數據中獲益,讓我們的線上項目更加穩定、和諧的跑在用戶電腦里。不過對于caniuse頁面上的一些細節,我們可能會感到困惑或者模棱兩可,今天就帶著大家一起來重新認識caniuse這個網站,并對它的原理和細節做些探究。

        1.1從babel-preset-env說起

        babel-preset-env是babel6中極力推崇的一個preset,preset代表的是babel plugins的一個集合,相當于一堆plugins的一個統稱。在babel最開始打江山的時候,es6標準也發布不久,babelrc的配置中只需要添加es2015這樣的preset。但隨著es2016、es2017的相繼出現,babelrc很快就會變成一堆掛歷式的集合體。所以babel給出了env這個殺器,既避免了es20xx的出現,又可以與caniuse的權威數據融合,讓配置preseet科學而簡單。

        {
          "presets": [
            ["env", {
              "targets": {
                "browsers": ["last 2 versions", "safari >= 7"]
              }
            }]
          ]
        }

        這是babel官網給出的env配置方案,"last 2 versions", "safari >= 7",這兩個條件是并集的關系,babel將會分別給出滿足這兩個條件的瀏覽器及版本,并會進行合并,最后算出一組瀏覽器及對應最低版本的數據。

        babel是用來轉換js語法的一個編譯器,為什么還能知道滿足env條件的瀏覽器跟版本,這要從browserslist這個庫說起.

        1.2 Browserslist

        這個庫不僅僅用在babel-preset-env中,像autoprefixer這樣知名的庫,也是用到了它。

        last 1 version
        > 1%
        maintained node versions
        not dead

        browserslist能夠把上面近似于人類語言的配置,轉換成一組瀏覽器集合。不過它的主要職責就是轉化上面的配置內容,按照正則過濾出正確瀏覽器列表內容,而它本身不提供瀏覽器列表的來源。

        1.3 caniuse-lite

        Browserslist的瀏覽器數據來源就是這個caniuse-lite,而它是caniuse-db庫的精簡版本,是從caniuse-db庫衍化而來,只不過對caniuse-db數據按照一定規則做了簡化,使得庫的大小減少了許多,并且提供一些查詢api供他人使用,每當caniuse-db更新時,也會跟著一起發布版本。

        1.4 caniuse-db

        caniuse的npm包,提供了caniuse網站查詢所需的所有數據。


        2.caniuse庫的介紹

        caniuse-db的github地址在此,caniuse鼓勵大家去github上提交pr,經過審核之后就可以被錄用到它的官方數據庫中。

        2.1如何為caniuse貢獻數據

        首先,它為我們準備了sample-data.json文件,按照此文件格式把需要增加的特性名稱、介紹和瀏覽器兼容性情況填寫清楚,保存并放到features-json文件夾中,最后提交pull request即可,審核完畢后會自動把這部分新增特性保存到data.json中。data.json就是caniuse官方的數據庫導出文件,供其他庫調用,每次json文件變化后,都會release一個新版本。

        2.2 sample-data.json

        作為新特性發布的樣本文件,內容如下:

        {
          "title":"Sample title",
          "description":"Sample description",
          "spec":"http://example.com/path/to/spec.html",
          "status":"wd",
          "links":[
            {
              "url":"http://example.com/path/to/link.html",
              "title":"Link title"
            }
          ],
          "bugs":[
            {
              "description":"Sample bug description"
            }
          ],
          "categories":[
            "CSS"
          ],
          "stats":{
            "ie":{
              ...
              "11":"u"
            },
            "edge":{
              ...
              "18":"u"
            },
            "firefox":{
              ...
              "67":"u"
            },
            "chrome":{
              ...
              "75":"u"
            },
            "safari":{
              ...
              "TP":"u"
            },
            "opera":{
              ...
              "58":"u"
            },
            "ios_saf":{
              ...
              "12.2":"u"
            },
            "op_mini":{
              "all":"u"
            },
            "android":{
              ...
              "67":"u"
            },
            "bb":{
              "7":"u",
              "10":"u"
            },
            "op_mob":{
              ...
              "46":"u"
            },
            "and_chr":{
              "71":"u"
            },
            "and_ff":{
              "64":"u"
            },
            "ie_mob":{
              ...
              "11":"u"
            },
            "and_uc":{
              "11.8":"u"
            },
            "samsung":{
              ...
              "8.2":"u"
            },
            "and_qq":{
              "1.2":"u"
            },
            "baidu":{
              "7.12":"u"
            }
          },
          "notes":"Sample notes for feature, explain partial support here",
          "notes_by_num":{
            "1":"First note..."
          },
          "usage_perc_y":0,
          "usage_perc_a":0,
          "ucprefix":false,
          "parent":"parentfeatureid",
          "keywords":"example,keywords",
          "shown":false,
          "ie_id":"",
          "chrome_id":"",
          "firefox_id":"",
          "webkit_id":""
        }

        簡要介紹下其中的幾個關鍵字段:

        (1)title:特性名稱
        (2)description:特性介紹(搜索時的關鍵字)
        (3)spec:跳轉到詳細介紹頁面
        (4)links:拓展內容介紹
        (5)keywords:搜索時的關鍵字
        (6)status:特性在標準中的狀態

        • ls - 標準
        • rec - W3C 推薦
        • pr - W3C 建議
        • cr - W3C 候選
        • wd - W3C 手稿
        • other - 非W3C, 但流行的
        • unoff - 非官方

        (7)categories:分類

        • HTML5
        • CSS
        • CSS2
        • CSS3
        • SVG
        • PNG
        • JS API
        • Canvas
        • DOM
        • Other
        • JS
        • Security

        從上面分類可以看出,caniuse并不只是一個查詢css兼容性的網站。

        如果想查看目前caniuse已經支持了多少種特性,以及特性對應的分組信息,可以點擊這個網址。

        (8)stats:瀏覽器對特性的支持情況

        • y - (Y)es, supported by default 完全支持
        • a - (A)lmost supported (aka Partial support) 部分支持
        • n - (N)o support, or disabled by default 不支持
        • p - No support, but has (P)olyfill 不支持,但有替代方案
        • u - Support (u)nknown 未知
        • x - Requires prefi(x) to work 需要加前綴
        • d - (D)isabled by default (need to enable flag or something)需要打flag
        • '#n' - Where n is a number, starting with 1, corresponds to the notes_by_num note. 支持,請看介紹第n條

        (9)stats:瀏覽器列表

        • ie
        • edge
        • firefox
        • chrome
        • safari
        • opera
        • ios_saf
        • op_mini
        • android
        • bb
        • op_mob
        • and_chr
        • and_ff
        • ie_mob
        • and_uc
        • samsung
        • and_qq
        • baidu

        以上瀏覽器列表是固定的,用戶不能增加和缺少某個瀏覽器類型。

        總結

        每當增加一個新特性時,都要對以上瀏覽器列表以及對應版本列表進行實測,特性的測試可使用以下兩個官方推薦的網站https://www.browserstack.comhttp://saucelabs.com。
        對于第二個網站,可用于因瀏覽器兼容性造成生產事故的還原測試,在其網站的虛擬機內完成特定瀏覽器特定版本的實測,在測試完成后可以觀看操作視頻,并支持導出功能,這對技術解決兼容性問題,提供了第一現場的操作流程,方便問題的解決。

        3.caniuse網站介紹

        3.1主頁面介紹

        clipboard.png
        頁面紅字標注了4個地方
        (1)代表了這個介紹框的內容隸屬于一個特性,也就是我們在features-json看到的一個個跟特性相關的文件,沒有#標志的不屬于特性。
        (2)代表這個特性在標準中所處的一個狀態,具體參照前文對sample-data.json的介紹
        (3)對于這個特性,在全球、中國所有瀏覽器中,分別有多少完全支持和部分支持,把兩部分值加起來,得到總份額。
        (4)瀏覽器基線,代表對應瀏覽器current狀態的版本號?;€往上是該瀏覽器的低版本,并對相同支持情況的版本進行合并?;€往下是未來的三個版本,并進行狀態合并。

        3.2瀏覽器信息統計

        caniuse關于瀏覽器的數據,主要都來源于statcounter,此網站統計了全球以及各國的瀏覽器使用情況。

        上面提到的瀏覽器基線及版本號列表,都是基于statcounter上個月份的數據統計。
        例如chrome v73在3月12號發布了版本,但在caniuse網站里,v72還是作為了current版本,就是因為caniuse的分析數據來源于2月份的統計數據,數據并不是實時更新。

        3.3詳情

        clipboard.png
        頁面紅字標注了4個地方
        (1)瀏覽器對特性支持情況相同的版本區間
        (2)對特性的支持情況
        (3)火狐40-火狐64的發布時間
        (4)火狐40-火狐64,在全球、中國的使用份額

        4.想法

        知道了caniuse的數據來源及原理之后,我們是否可以打造屬于自己公司的caniuse,暫且就叫做caniuse-shein

        (1)
        目前,我司的前端只負責中后臺系統,面向的用戶群體有限。
        而我手頭上有一個專門為公司前端而打造的APM項目,里面包含了詳盡的瀏覽器版本及份額數據,將APM項目中的瀏覽器數據與caniuse的特性數據相結合,可以制作出類似于caniuse官網的特性查詢分析頁面,但報表數據只關心我司的用戶群里使用的瀏覽器,而非依據全球或者全國。

        (2)
        babel-preset-env這個插件也可以結合caniuse-shein的數據,給出對應瀏覽器份額的babel插件列表

        招聘

        1. 有想找工作的前端朋友,可以投遞【字節跳動】,base全國,目前海量HC,從速投遞。請掃描下圖獲取所有崗位列表

        image

        2.另外有想了解招聘詳情的同學也可加我微信 stoneyAllen

        查看原文

        kruz 贊了回答 · 2020-02-23

        解決如何在ie11里使用a連接創建動態下載文件流?

        查了資料,可以使用微軟獨家的msSaveBlob, 這個方法支持ie10及以上。

        var downloadFileName = self.formatTimestamp()+ '-' + self.logFilename;
        
                if(window.navigator.msSaveBlob){
                    // for ie 10 and later
                    try{
                        var blobObject = new Blob([self.output]); 
                        window.navigator.msSaveBlob(blobObject, downloadFileName); 
                    }
                    catch(e){
                        console.log(e);
                    }
                }
                else{
                    var file = "data:text/plain;charset=utf-8,";
                    var logFile = self.output;
                    var encoded = encodeURIComponent(logFile);
                    file += encoded;
                    var a = document.createElement('a');
                    a.href = file;
                    a.target   = '_blank';
                    a.download = downloadFileName;
                    document.body.appendChild(a);
                    a.click();
                    a.remove();
                }
        

        關注 2 回答 1

        kruz 贊了問題 · 2020-02-23

        解決如何在ie11里使用a連接創建動態下載文件流?

        下面的函數,在其他瀏覽器里可以下載一個txt文件,但是在ie11里跳轉到一個空白頁面。文件被url編碼后放在了地址欄。沒有觸發下載。請問怎么才能在ie11里也觸發下載文件?

        完整項目地址:https://github.com/wangduandu...

            this.downloadLog = function() {
                var file = "data:text/plain;charset=utf-8,";
                var logFile = self.getLog();
                var encoded = encodeURIComponent(logFile);
                file += encoded;
                var a = document.createElement('a');
                a.href = file;
                a.target   = '_blank';
                a.download = self.formatTimestamp()+ '-' + self.logFilename;
                document.body.appendChild(a);
                a.click();
                a.remove();
            };

        圖片描述圖片描述

        關注 2 回答 1

        認證與成就

        • 獲得 0 次點贊
        • 獲得 2 枚徽章 獲得 0 枚金徽章, 獲得 0 枚銀徽章, 獲得 2 枚銅徽章

        擅長技能
        編輯

        (??? )
        暫時沒有

        開源項目 & 著作
        編輯

        (??? )
        暫時沒有

        注冊于 2017-05-12
        個人主頁被 301 人瀏覽

        一本到在线是免费观看_亚洲2020天天堂在线观看_国产欧美亚洲精品第一页_最好看的2018中文字幕