作者 / Michael Thomsen, Dart & Flutter Product Manager, Google
我們已經正式發布了 Dart SDK 的 2.15 版本,該版本新增了可快速并發的工作器 isolate、新的構造函數拆分 (tear-off) 語言特性、經過改進的 dart:core 庫枚舉支持、package 發布者相關的新功能,等等。
工作器 isolate 的快速并發
如今,幾乎所有現代設備都使用多核 CPU,可以并行執行多個任務。對于大多數 Dart 程序來說,這些內核的使用情況對開發者而言是透明的: 默認情況下,Dart 運行時系統在單個內核上運行所有的 Dart 代碼,不過會使用其他內核來執行系統級任務,比如異步輸入/輸出,包括寫入文件或者調用網絡等。
不過您自己的 Dart 代碼可能也需要并發運行。例如,您可能需要展示一個連續的動畫,同時執行一個長時間運行的任務,比如解析一個大型 JSON 文件。如果額外任務花了太長時間,就可能會導致界面卡頓或延遲。如果將這些額外的任務移動到另一個單獨的內核,動畫就可以在主執行線程上繼續運行而不受干擾。
Dart 的并發模型基于 isolate,isolate 是一種相互隔離的獨立執行單元,這是為了避免出現與共享內存相關的大量并發編程錯誤,如數據爭用等競態條件。Dart 通過禁止在 isolate 之間共享任何可變對象來避免這些錯誤,并使用消息傳遞在 isolate 之間交換狀態。在 Dart 2.15 中,我們對 isolate 進行了許多實質性的改進。
Dart 中的并發 https://dart.dev/guides/language/concurrency
競態條件 https://en.wikipedia.org/wiki/Race_condition#In_software
在 isolate 間發送多條消息 https://dart.dev/guides/language/concurrency#sending-multiple-messages-between-isolates
我們首先重新設計和實現了 isolate 的工作方式,引入了一個新概念: isolate 組。Isolate 組中的 isolate 共享各種內部數據結構,這些數據結構則表示正在運行的程序。這使得組中的單個 isolate 變得更加輕便。如今,因為不需要初始化程序結構,在現有 isolate 組中啟動額外的 isolate 比之前快 100 多倍,并且產生的 isolate 所消耗的內存減少了 10 至 100 倍。
雖然 isolate 組仍然阻止在 isolate 間共享訪問可變對象,但由于 isolate 組使用共享堆實現,這也讓其擁有了更多的功能。我們可以將對象從一個 isolate 傳遞到另一個 isolate,這可用于執行返回大量內存數據的任務的工作器 isolate。例如,工作器 isolate 通過網絡調用獲得數據,將該數據解析為大型 JSON 對象圖,然后將這個 JSON 圖返回到主 isolate 中。在推出 Dart 2.15 之前,執行該操作需要深度復制,如果復制花費的時間超過幀預算時間,就會導致界面卡頓。
在 Dart 2.15 中,工作器 isolate 可以調用 Isolate.exit(),將其結果作為參數傳遞。然后,Dart 運行時將包含結果的內存數據從工作器 isolate 傳遞到主 isolate 中,無需復制,且主 isolate 可以在固定時間內接收結果。我們已經在 Flutter 2.8 中更新了 compute() 實用函數,來利用 Isolate.exit()。如果您已經在使用 compute(),那么在升級到 Flutter 2.8 后,您將自動獲得這些性能提升。
Isolate.exit() https://api.dart.cn/stable/2.15.0/dart-isolate/Isolate/exit.html
compute() https://api.flutter-io.cn/flutter/foundation/compute-constant.html
最后,我們還重新設計了 isolate 消息傳遞機制的實現方式,使得中小型消息的傳遞速度提高了大約 8 倍。發送消息的速度明顯更快,而接收信息幾乎總是在恒定的時間內完成。另外,我們擴展了 isolate 可以相互發送的對象種類,增加了對函數類型、閉包和堆棧跟蹤對象的支持。請參閱 SendPort.send() 的 API 文檔了解詳情:
https://api.dart.cn/stable/2.15.0/dart-isolate/SendPort/send.html
要了解有關如何使用 isolate 的更多信息,請參閱我們為 Dart 2.15 添加的官方文檔 Dart 中的并發,以及更多代碼示例。
Dart 中的并發 https://dart.cn/guides/language/concurrency
代碼示例 https://github.com/dart-lang/samples/tree/master/isolates
新語言特性:構造函數拆分
在 Dart 中,您可以使用函數名稱創建一個函數對象,該對象指向另一個對象的函數。在以下示例中,main() 方法的第二行演示了將 g 指向 m.greet 的語法:
class Greeter { final String name; Greeter(this.name); void greet(String who) { print('$name says: Hello $who!'); }}void main() { final m = Greeter('Michael'); final g = m.greet; // g holds a function pointer to m.greet. g('Leaf'); // Invokes and prints "Michael says: Hello Leaf!"}
在使用 Dart 核心庫時,這種函數指針 (也被稱為函數拆分) 經常出現。下面是通過傳遞函數指針在 iterable 上調用 foreach() 的示例:
final m = Greeter('Michael');['Lasse', 'Bob', 'Erik'].forEach(m.greet);// Prints "Michael says: Hello Lasse!", "Michael says: Hello Bob!",// "Michael says: Hello Erik!"
在之前的版本中,Dart SDK 不支持創建構造函數的拆分 (語言問題 #216)。這就有點煩人,因為在許多情況下,例如構建 Flutter 界面時,就需要用到構造函數的拆分。從 Dart 2.15 開始,我們支持這種語法。以下是構建包含三個 Text widget 的 Column widget 的示例,通過調用 .map() 將 Text 構造函數的拆分傳遞給 Column 的子項。
class FruitWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Column( children: ['Apple', 'Orange'].map(Text.new).toList()); }}
#216: 允許像傳遞方法一樣傳遞構造函數
https://github.com/dart-lang/language/issues/2
Text.new 指 Text 類的默認構造函數。您也可以引用命名構造函數,例如 .map(Text.rich)。
相關語言變化
在實現構造函數拆分時,我們也借此機會修復了現有的函數指針功能中的一些不一致問題。現在可以特化泛型方法來創建非泛型方法:
T id(T value) => value;var intId = id ; // New in 2.15.int Function(int) intId = id; // Pre-2.15 workaround.
您甚至可以特化一個泛型函數對象來創建一個非泛型函數對象:
const fo = id; // Tear off `id`, creating a function object.const c1 = fo; // New in 2.15; error before.
最后,Dart 2.15 清理了涉及泛型的類型字面量:
var y = List; // Already supported.var z = List; // New in 2.15.var z = typeOf >(); // Pre-2.15 workaround.
改進 dart:core 庫中的枚舉
我們為 dart:core 庫的枚舉 API 添加了許多優化 (語言問題 #1511)。現在您可以通過 .name 獲取每個枚舉值的 String 值:
enum MyEnum { one, two, three}void main() { print(MyEnum.one.name); // Prints "one".}
#1511: 為枚舉值添加 name 實例屬性 https://github.com/dart-lang/language/issues/1511
還可以按名稱查找枚舉值:
print(MyEnum.values.byName('two') == MyEnum.two); // Prints "true".
最后,您可以獲得所有名稱-值對的映射:
final map = MyEnum.values.asNameMap();print(map['three'] == MyEnum.three); // Prints "true".
請參閱此 Flutter PR 查看這些新 API 的使用示例:
https://github.com/flutter/flutter/pull/94496/files
壓縮指針
Dart 2.15 增加了對壓縮指針的支持,這樣,如果只需要支持 32 位的地址空間 (最多 4 GB 內存),則 64 位 SDK 可以使用更加節省空間的指針表示形式。壓縮指針顯著減少了內存占用,在對 Google Pay 應用的內部測試中,我們發現 Dart 堆的體積減少了大約 10%。
壓縮指針意味著無法處理 4 GB 以上的可用 RAM,因此該功能只存在于 Dart SDK 的配置選項中,只能在構建 SDK 時由 Dart SDK 的嵌入器啟用。Flutter SDK 2.8 版已為 Android 構建啟用此配置,Flutter 團隊正在考慮在后續版本中為 iOS 構建啟用此配置:
https://github.com/flutter/flutter/issues/94753
Dart SDK 中包含 Dart DevTools
以往 Dart SDK 不提供調試和性能工具的 DevTools 套件,您需要單獨下載。從 Dart 2.15 開始,下載 Dart SDK 時也會獲取 DevTools,無需進一步的安裝步驟。有關在 Dart 命令行應用中使用 DevTools 的更多信息,請參閱 DevTools 文檔:
https://dart.dev/tools/dart-devtools#using-devtools-with-a-command-line-app
DevTools套件
https://dart.dev/tools/dart-devtools#
面向 package 發布者的新 pub 功能
Dart 2.15 SDK 在 dart pub 開發者命令和 pub.devpackage repo 中還新增了兩個功能。 首先,為 package 發布者新增了一個安全功能,用于檢測發布者在 pub package 中意外發布 secret,例如 Cloud 或 CI 憑據。在了解到 GitHub repo 中每天都有數以千計的 secret 被泄露后,我們便決定添加這個泄露檢測功能。
公共 GitHub repo 的 secret 泄漏有多嚴重?
https://www.ndss-symposium.org/wp-content/uploads/2019/02/ndss2019_04B-3_Meli_paper.pdf
泄露檢測作為 dart pub publish 命令中的預發布驗證的一部分運行。如果它在即將發布的文件中檢測到潛在的 secret,publish 命令會退出,而不進行發布,并打印如下輸出:
Publishing my_package 1.0.0 to https://pub.dartlang.org:Package validation found the following errors:* line 1, column 1 of lib/key.pem: Potential leak of Private Key detected.?1 │ ┌ - - -BEGIN PRIVATE KEY - - -2 │ │ H0M6xpM2q+53wmsN/eYLdgtjgBd3DBmHtPilCkiFICXyaA8z9LkJ3 │ └ - - -END PRIVATE KEY - - -?* line 2, column 23 of lib/my_package.dart: Potential leak of Google OAuth Refresh Token detected.?2 │ final refreshToken = "1//042ys8uoFwZrkCgYIARAAGAQSNwF-L9IrXmFYE-sfKefSpoCnyqEcsHX97Y90KY-p8TPYPPnY2IPgRXdy0QeVw7URuF5u9oUeIF0";
在極少數情況下,此項檢測可能會出現誤報,將您實際上打算發布的內容或文件標記為潛在泄露。在這些情況下,您可以將文件添加到許可名單中:
https://dart.cn/tools/pub/pubspec#false_secrets
其次,我們還為發布者添加了另一個功能:撤銷已發布的 package 版本。當發布了有問題的 package 版本時,我們通常的建議是發布一個小幅升級的新版本來修復意外問題。但在極少數情況下,例如您尚未修復這些問題,或是您在原打算只發布一個次要版本時意外發布了一個主要版本,那么您就可以使用新的 package 撤銷功能,作為最后的補救方法。此功能在 pub.dev 的管理界面中提供:
撤銷 package 版本
https://dart.cn/tools/pub/publishing#retract
在 package 版本被撤銷后,pub 客戶端在 pub get 或 pub upgrade 中將不再解析該版本。如果有開發者已經解析該撤銷的版本 (并存在于他們的 pubspec.lock 文件中),他們將在下次運行 pub 時看到警告:
$ dart pub getResolving dependencies…mypkg 0.0.181-buggy (retracted, 0.0.182-fixed available)Got dependencies!
檢測雙向 Unicode 字符的安全性分析 (CVE-2021–22567)
最近發現了一個涉及雙向 Unicode 字符的通用編程語言漏洞 (CVE-2021–42574)。這個漏洞影響了大多數支持 Unicode 的現代編程語言。下面的 Dart 源代碼演示了這個問題:
main() { final accessLevel = 'user'; if (accessLevel == 'user .?// Check if admin? ?') { print('You are a regular user.'); } else { print('You are an admin.'); }}
CVE-2021–42574 https://nvd.nist.gov/vuln/detail/CVE-2021-42574
您可能會認為該程序會打印出 You are a regular user.,但實際上它打印出的是 You are an admin.!通過使用包含雙向 Unicode 字符的字符串,您就可能會造成這一漏洞。這些雙向字符針對在同一行的文本,可以將文本的方向由從左到右更改為從右到左,反之亦然。雙向字符文本在屏幕上的呈現與實際文本內容截然不同。您可以進一步查看此 GitHub gist 示例:
https://gist.github.com/mit-mit/7dda00ca6278ce7d2555f78d59d9e67b?h=1
針對此漏洞的緩解措施包括使用檢測雙向 Unicode 字符的工具 (編輯器、代碼審查工具等),以便開發者發現它們,并在知情的情況下使用這些字符。上面提到的 GitHub gist 文件查看器便是發現這些字符的工具的一個例子。
Dart 2.15 引入了進一步的緩解措施 (Dart 安全建議CVE-2021–22567)。現在,Dart 分析器會掃描雙向 Unicode 字符,并標記對它們的任何使用:
$ dart analyzeAnalyzing cvetest... 2.6sinfo ? bin/cvetest.dart:4:27 ? The Unicode code point 'U+202E' changes the appearance of text from how it's interpreted by the compiler. Try removing the code point or using the Unicode escape sequence 'u202E'. ? text_direction_code_point_in_literal
Dart 安全建議 CVE-2021–22567 https://github.com/dart-lang/sdk/security/advisories/GHSA-8pcp-6qc9-rqmv
我們建議用 Unicode 轉義序列替換這些字符,這樣它們就可在任何文本編輯器或查看器中顯示出來。或者,如果您確實正當使用了這些字符,您可以在使用這些字符的代碼行之前添加覆蓋語句來禁用警告:
// ignore: text_direction_code_point_in_literal
使用第三方 pub 服務器時的 pub.dev 憑據漏洞 (CVE-2021–22568)
我們也發布了第二個與 pub.dev 相關的 Dart 安全建議:CVE-2021–22568。此建議針對可能將 package 發布到第三方 pub package 服務器 (例如私人或公司內部 package 服務器) 的 package 發布者。僅將 package 發布到公開 pub.dev repo (標準配置) 的開發者不受此漏洞的影響。
CVE-2021–22568 https://github.com/dart-lang/sdk/security/advisories/GHSA-r32f-vhjp-qhj7
如果您已經將 package 發布至第三方 repo,那么漏洞是:用于在第三方 repo 進行身份驗證的 OAuth2 臨時 (一小時) 訪問令牌可能被誤用,以在公開 pub.dev repo 上進行身份驗證。因此惡意的第三方 pub 服務器可能會使用訪問令牌,在 pub.dev 上冒充您,并發布 package。如果您已經將 package 發布到一個不受信任的第三方 package repo,請考慮審查您的帳號在 pub.dev 公開 package repo 上的所有活動。我們推薦您使用 pub.dev 活動日志進行查看:
https://pub.dev/my-activity-log
最后
希望您喜歡已經推出的 Dart 2.15 中的新功能。這是我們今年的最后一個版本,我們想借此機會表達我們對美妙的 Dart 生態系統的感謝。感謝大家的寶貴反饋,以及對我們一直以來的支持,感謝大家在過去的一年中在 pub.dev 上發布的數千個 package,它們豐富了我們的生態系統。我們迫切期待明年再次投入工作,我們計劃在 2022 年推出很多激動人心的內容。預祝大家新年快樂,好好享受即將到來的假期吧!
原文標題:Dart 2.15 現已發布
文章出處:【微信公眾號:谷歌開發者】歡迎添加關注!文章轉載請注明出處。
-
函數
+關注
關注
3文章
4346瀏覽量
62971 -
SDK
+關注
關注
3文章
1045瀏覽量
46271 -
GitHub
+關注
關注
3文章
473瀏覽量
16564
原文標題:Dart 2.15 現已發布
文章出處:【微信號:Google_Developers,微信公眾號:谷歌開發者】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論