如何快速入門VUE3.0:進入學習
多個上下文存取SharedArrayBuffer時,如果同時對緩衝區執行操作,就可能出現資源爭用問題。 Atomics API 透過強制同一時刻只能對緩衝區執行一個操作,可以讓多個上下文安全地讀寫一個SharedArrayBuffer。
原子操作的本質會排斥作業系統或電腦硬體通常會自動執行的最佳化(例如指令重新排序)。原子操作也讓並發存取記憶體變得不可能,如果應用不當就可能導致程式執行變慢,為此,Atomics API 的設計初衷是在最少但很穩定的原子行為基礎上,建立複雜的多執行緒JavaScript程序。
Atomics API 提供了一套簡單的方法來執行就地修改操作。在ECMA規範中,這些方法被定義為AtomicReadModifyWrite操作。在底層,這些方法都會從SharedArrayBuffer中某個位置讀取值,然後執行算術和位元操作,最後再把計算結果寫到相同的位置。這些操作的原子本質意味著上述讀取、修改、寫回操作會依序執行,不會被其它執行緒中斷。
//建立大小為1的緩衝區let sharedArrayBuffer = new SharedArrayBuffer(1); //基於緩衝建立Unit8Arraylet typedArray = new Unit8Array(sharedArrayBuffer); //所有ArrayBuffer全部初始化為0console.log(typedArray); //Unit8Array[0] //對索引0處的值執行原子加10Atomics.add(typedArray,0,10); //Unit8Array[10] //對索引0處的值執行原子減10Atomics.sub(typedArray,0,10); //Unit8Array[0]
瀏覽器的JavaScript編譯器和CPU架構本身都有權限重排指令以提升程式執行效率。正常情況下,JavaScript的單執行緒環境是可以隨時進行這種最佳化的,但是,多執行緒中的指令重排可能導致資源爭用,而且極難排錯。
Atomics API 透過兩種主要方式解決這個問題:
所有原子指令相互之間的順序永遠不會重排。
使用原子讀或原子寫保證所有指令都不會相對原子讀寫重新排序。
除了讀寫緩衝區的值,Atomics.load()和Atomics.store()還可以建構「程式碼圍欄」。 JavaScript引擎保證非原子指令可以相對於load()和store()本地重排,但這個重排不會侵犯原子讀寫的邊界。
const sharedArrayBuffer = new SharedArrayBuffer(4); const view = new Unit32Array(sharedArrayBuffer); //執行非原子寫view[0] = 1; //非原子寫可以保證在這個讀取操作之前完成,所以這裡一定會讀到1console.log(Atomics.load(view,0)); //1 //執行原子寫Atomics.store(view,0,2); //非原子讀可以保證在原子寫完成後發生,這裡一定會讀到2console.log(view[0]); //2
為了確保連續、不間斷的先讀後寫,Atomics API 提供了兩種方法:exchange()和compareExchange()。 Atomics.exchange()執行簡單的交換,以確保其他執行緒不會中斷值得交換。
const sharedArrayBuffer = new SharedArrayBuffer(4); const view = new Unit32Array(sharedArrayBuffer); //在索引0處寫入10Atomics.store(view,0,10); //從索引0處讀取值,然後在索引0處寫入5console.log(Atomics.exchange(view,0,5)); //10 //從索引0處讀取值console.log(Atomics.load(view,0)); //5
在多執行緒程式中,一個執行緒可能只希望在上次讀取某個值之後沒有其他執行緒修改該值得情況下對共享緩衝區執行寫入操作。如果這個值沒有被修改,這個執行緒就可以安全地寫入更新後的值:如果這個值被修改了,那麼執行寫入操作將會破壞其他執行緒計算的值。對於這個任務,Atomics API提供了compare-Exchange()方法。這個方法只在目標索引處的值與預期值相符時才會執行寫入操作。
如果沒有某種鎖機制,多執行緒程式就無法支援複雜需求。為此,Atomics API提供了模仿Linux Futex(快速用戶空間互斥量,fast user-space mutex)的方法。這些方法本身雖然非常簡單,但可以作為更複雜鎖機制的基本組件。
所有原子Futex操作只能用於Int32Array視圖,而且,只能用在工作執行緒內部。
跨文件訊息,有時也稱為XDM(cross-document messaging),是一種在不同執行上下文(例如不同工作執行緒或不同來源的頁面)間傳遞訊息的能力。
Encoding API主要用於實作字串與定型陣列之間的轉換。
File API仍然以表單中的文件輸入欄位為基礎,但是增加了直接存取文件資訊的能力。 HTML5在DOM上為檔案輸入元素增加了files集合。當使用者在文件欄位中選擇一個或多個文件時,這個files集合中會包含一組File對象,表示被選中的文件,每個File對像都有一些唯讀屬性。
FileReader類型表示一種非同步檔案讀取機制,可以把FileReader想像成類似XMLHttpRequest,只不過用於從檔案系統讀取文件,而不是從伺服器讀取資料。 FileReader類型提供了幾種讀取檔案資料的方法。
readAsText(file,encoding);//從檔案讀取純文字內容並儲存在result屬性中
readAsDataURL(file);//讀取檔案並將內容的資料URI儲存在result屬性中
readAsBinaryString(file);/ /讀取檔案並將每個字元的二進位資料保存在result屬性中
readAsArrayBuffer(file);//讀取檔案並將檔案內容以ArrayBuffer形式保存在result屬性中
FileReader類型的同步版本。
某些情況下,可能需要讀取部分文件而不是整個文件,為此,File物件提供了一個名為slice()的方法。 slice()方法接收兩個參數:起始位元組和堯都區的位元組數。這個方法傳回一個Blob的實例,而Blob其實是File的超類別。
blob表示二進位大對象,是JavaScript對不可修改二進位資料的封裝型別。包含字串的陣列、ArrayBuffers、ArrayBufferViews,甚至其他Blob都可以用來建立blob。 Blob建構函式可以接收一個options參數,並在其中指定MIME型別。
Streams API 是為了解決一個簡單但又很基礎的問題而生的:Web應用如何消費有序的小資訊區塊而不是大塊資訊?這種能力主要有兩種應用場景。
Streams API定義了三種流:
可讀流:可以透過某個公共介面讀取資料塊的流。資料在內部從底層來源進入流,然後由消費者consumer進行處理。
可寫流:可以透過某個公共介面寫入資料塊的流。生產者(consumer)將資料寫入流,資料在內部傳入底層資料槽(sink)。
轉換流:由兩種流組成,可寫入流用於接收數據,可讀流用於輸出資料。這兩個流質檢測是轉換程序(transformer),可以根據需要檢查和修改流內容。
Web Cryptography API描述了一套密碼學工具,規範了JavaScript如何以安全和符合慣例的方式實現加密。這些工具包括產生、使用和應用加密秘鑰對,加密和解密訊息,以及可靠地產生隨機數。
在需要產生隨機數字時,很多人會使用Math.random()
。這個方法在瀏覽器中是以偽隨機數產生器(PRNG,PseudoRandom Number Generator)方式實現的。所謂的偽指的是生成值的過程不是真的隨機。 PRNG產生的值只是模擬了隨機的特性。瀏覽器的PRNG並未使用真正的隨機來源,只是對一個內部狀態應用了固定的演算法。每次呼叫Math.random()
,這個內部狀態都會被一個演算法修改,而結果會轉換為一個新的隨機數。例如,V8引擎使用了一個名為xorshift128+
的演算法來執行這種修改。
由於演算法本身是固定的,其輸入只是先前的狀態,因此隨機數順序也是決定的。 xorshift128+
使用128位元內部狀態,而演算法的設計讓任何初始狀態在重複自身之前都會產生2 128 -1個偽隨機值。這種循環稱為置換循環,而這個循環的長度稱為一個週期。很明顯,如果攻擊者知道PRNG的內部狀態,就可以預測後續產生的偽隨機值。如果開發者無意間使用了PRNG產生了私有金鑰來加密,則攻擊者就可以利用PRNG的這個特性來算出私有金鑰。
偽隨機數產生器主要用於快速計算出看起來隨機的數,不過並不適合用於加密演算法,為解決這個問題,密碼學安全偽隨機數產生器(CSPRNG,Cryptographically Secure PseudoRandom Number Generator),額外增加了一個熵作為輸入,例如測試硬體時間或其它無法預期行為的系統特性,雖然速度上不及PRNG,但是產生的值更難預測了,就可以用於加密。
Web Cryptography API引進了CSPRNG,這個CSPRNG可以透過crypto.getRandomValues()
在全域Crypto
物件上存取。與Math.random()
傳回一個0到1之間的浮點數不同, getRandomValues()
會把隨機值寫入作為參數傳給它的定型陣列。定型數組的類別不重要,因為底層緩衝區會被隨機的二進位位元填滿。