成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

V8 JavaScript 引擎:高性能的 ES2015+

songze / 2967人閱讀

摘要:最后,客戶端只是依賴于引擎的環(huán)境之一。新的編譯器管道利用來(lái)實(shí)現(xiàn),并生成可以轉(zhuǎn)換生成器控制流到簡(jiǎn)單的本地控制流的字節(jié)碼??梢愿菀椎貎?yōu)化所得到的字節(jié)碼,因?yàn)樗恍枰狸P(guān)于生成器控制流的任何具體內(nèi)容,只是如何保存和恢復(fù)函數(shù)的狀態(tài)。

本文轉(zhuǎn)載自:眾成翻譯
譯者:smartsrh
鏈接:http://www.zcfy.cc/article/2978
原文:https://v8project.blogspot.sg/2017/02/high-performance-es2015-and-beyond.html

在過(guò)去的幾個(gè)月中,V8 團(tuán)隊(duì)一直努力讓新增的 ES2015 和其它更前沿的 JavaScript 功能的性能達(dá)到等效的 ES5的水平。

動(dòng)機(jī)

在我們?cè)敿?xì)介紹各種改進(jìn)之前,我們首先應(yīng)該考慮為什么 ES2015+ 功能的性能很重要,盡管 Babel 在現(xiàn)代 Web 開發(fā)中得到廣泛的應(yīng)用:

首先,有的 ES2015 功能是按需解析成 ES5 的,例如內(nèi)置的 Object.assign 。 當(dāng) Babel 編譯對(duì)象擴(kuò)展語(yǔ)法(應(yīng)用在大量 React 和 Redux 程序)并且編譯器也支持這個(gè)語(yǔ)法時(shí),Babel 會(huì)使用 Object.assign 而棄用等效的 ES5 代碼。

將 ES2015 功能解析成 ES5 通常會(huì)增加大量代碼,加劇了當(dāng)前的 Web 性能危機(jī),尤其不利于新興市場(chǎng)上常見(jiàn)的千元機(jī)。因此,即使在考慮實(shí)際執(zhí)行成本之前,傳輸、解析和編譯代碼的成本就相當(dāng)高。

最后,客戶端JavaScript只是依賴于V8引擎的環(huán)境之一。 還有用于服務(wù)器端應(yīng)用程序和工具的 Node.js,開發(fā)人員不需要將代碼解析成 ES5,可以直接使用目標(biāo) Node.js 版本中相關(guān) V8 版本支持的功能。

讓我們考慮以下節(jié)選自 Redux 文檔中的代碼段:

 function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return { ...state, visibilityFilter: action.filter }
    default:
      return state
  }
}

該代碼中有兩處需要解析成 ES5:state 的默認(rèn)參數(shù)和 state 的擴(kuò)展對(duì)象語(yǔ)法。Babel 生成以下 ES5 代碼:

 "use strict";

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

function todoApp() {
  var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialState;
  var action = arguments[1];

  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return _extends({}, state, { visibilityFilter: action.filter });
    default:
      return state;
  }
}

現(xiàn)在假如 Object.assign比 Babel 生成的 polyfilled_extends 要慢好幾個(gè)數(shù)量級(jí)。在這種情況下,從不支持 Object.assign 的瀏覽器升級(jí)到支持 ES2015 的瀏覽器版本將大幅降低性能,可能會(huì)阻礙 ES2015 的普及。

此示例還體現(xiàn)了解析成 ES5 的另一個(gè)重要缺點(diǎn):發(fā)送給用戶的代碼通常遠(yuǎn)大于開發(fā)人員最初編寫的 ES2015+ 代碼。在上面的示例中,原始代碼是 203 字符(gzip 壓縮后 176 字節(jié)),而生成的代碼是 588 字符(gzip 壓縮后 367 字節(jié))。體積增長(zhǎng)了兩倍。 我們來(lái)看看 Async Iterators for JavaScript 的另一個(gè)例子:

 async function* readLines(path) {
  let file = await fileOpen(path);

  try {
    while (!file.EOF) {
      yield await file.readLine();
    }
  } finally {
    await file.close();
  }
}

Babel 將以上 187 字符(gzip 壓縮后 150 字節(jié))解析成 2987 字符的 ES5 代碼(gzip 壓縮后 971 字節(jié)),這里還沒(méi)考慮所需依賴的 regenerator runtime :

 "use strict";

var _asyncGenerator = function () { function AwaitValue(value) { this.value = value; } function AsyncGenerator(gen) { var front, back; function send(key, arg) { return new Promise(function (resolve, reject) { var request = { key: key, arg: arg, resolve: resolve, reject: reject, next: null }; if (back) { back = back.next = request; } else { front = back = request; resume(key, arg); } }); } function resume(key, arg) { try { var result = gen[key](arg); var value = result.value; if (value instanceof AwaitValue) { Promise.resolve(value.value).then(function (arg) { resume("next", arg); }, function (arg) { resume("throw", arg); }); } else { settle(result.done ? "return" : "normal", result.value); } } catch (err) { settle("throw", err); } } function settle(type, value) { switch (type) { case "return": front.resolve({ value: value, done: true }); break; case "throw": front.reject(value); break; default: front.resolve({ value: value, done: false }); break; } front = front.next; if (front) { resume(front.key, front.arg); } else { back = null; } } this._invoke = send; if (typeof gen.return !== "function") { this.return = undefined; } } if (typeof Symbol === "function" && Symbol.asyncIterator) { AsyncGenerator.prototype[Symbol.asyncIterator] = function () { return this; }; } AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); }; AsyncGenerator.prototype.throw = function (arg) { return this._invoke("throw", arg); }; AsyncGenerator.prototype.return = function (arg) { return this._invoke("return", arg); }; return { wrap: function wrap(fn) { return function () { return new AsyncGenerator(fn.apply(this, arguments)); }; }, await: function await(value) { return new AwaitValue(value); } }; }();

var readLines = function () {
  var _ref = _asyncGenerator.wrap(regeneratorRuntime.mark(function _callee(path) {
    var file;
    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.next = 2;
            return _asyncGenerator.await(fileOpen(path));

          case 2:
            file = _context.sent;
            _context.prev = 3;

          case 4:
            if (file.EOF) {
              _context.next = 11;
              break;
            }

            _context.next = 7;
            return _asyncGenerator.await(file.readLine());

          case 7:
            _context.next = 9;
            return _context.sent;

          case 9:
            _context.next = 4;
            break;

          case 11:
            _context.prev = 11;
            _context.next = 14;
            return _asyncGenerator.await(file.close());

          case 14:
            return _context.finish(11);

          case 15:
          case "end":
            return _context.stop();
        }
      }
    }, _callee, this, [[3,, 11, 15]]);
  }));

  return function readLines(_x) {
    return _ref.apply(this, arguments);
  };
}();

代碼體積增加了 650%_asyncGenerator 函數(shù)是可復(fù)用的,具體取決于捆綁代碼的方式,因此可以在多個(gè)異步迭代器使用中減小一些代碼的體積)。我們不認(rèn)為將代碼解析成 ES5 可以解決所有問(wèn)題,因?yàn)榇a體積的增加不僅會(huì)影響下載時(shí)間/成本,還會(huì)增加解析和編譯的額外開銷。如果我們真的想大幅度地改善現(xiàn)代 Web 應(yīng)用程序的頁(yè)面加載和緩存(特別是在移動(dòng)設(shè)備上)的效率,我們必須鼓勵(lì)開發(fā)人員在編寫代碼時(shí)不僅使用 ES2015+,并且不需解析成 ES5 就直接發(fā)送給客戶端,只向不支持 ES2015 的傳統(tǒng)瀏覽器提供完全解析的代碼。對(duì)于編譯器的作者而言,這一想法意味著我們需要直接支持 ES2015+ 功能,提供合理的性能。

測(cè)試方法

如上所述,ES2015+ 功能的絕對(duì)性能并不是主要矛盾。相反,目前應(yīng)優(yōu)先確保 ES2015+ 功能的性能與等效的原生 ES5 代碼相當(dāng),更重要的是和 Babel 生成的代碼性能相當(dāng)。Kevin Decker 有一個(gè)項(xiàng)目叫 six-speed,它或多或少可以滿足我們的需求:ES2015 功能與等效的原生 ES5 代碼與解析后產(chǎn)生的 ES5 代碼之間的性能比較。

所以我們決定用它作為我們開始 ES2015+ 性能工作的基礎(chǔ)。我們拷貝了該項(xiàng)目并添加了一些測(cè)試。 我們首先關(guān)注性能最差的部分,比如說(shuō)列表項(xiàng),原生的 ES5 比 ES2015+ 版本效率高 2 倍,因?yàn)槲覀兊幕炯僭O(shè)是原生的 ES5 版本至少與 Babel 的版本一樣快。

一個(gè)為現(xiàn)代語(yǔ)言而生的現(xiàn)代架構(gòu)

過(guò)去,V8 很難改善 ES2015+ 功能的優(yōu)化,例如,給 Crankshaft —— V8 的經(jīng)典優(yōu)化編譯器—— 添加異常處理(比如 try/catch/finally)是不可行的。 這意味著 V8 優(yōu)化 ES6 功能像 for...of 之類的的能力是有限的,因?yàn)樗举|(zhì)上是一個(gè)隱含的 finally 子句。Crankshaft 的局限性以及將全新的語(yǔ)言功能添加到全代碼(V8 的基準(zhǔn)編譯器)中的整體復(fù)雜性,使得 V8 難添加和優(yōu)化剛剛標(biāo)準(zhǔn)化的新 ES 功能。

幸運(yùn)的是,V8 的新的解釋器 Ignition 和編譯器管道 TurboFan 從一開始就著手支持整個(gè) JavaScript 語(yǔ)言,包括高級(jí)控制流程,異常處理以及 ES2015 的最新版本和解構(gòu)賦值。Ignition 和 TurboFan 架構(gòu)的緊密結(jié)合可以快速添加新功能并逐步進(jìn)行優(yōu)化。

對(duì)于許多現(xiàn)代的 ES 功能和改進(jìn)只有在新的 Ignition 和 TurboFan 下才可行。 Ignition 和 TurboFan 對(duì)于優(yōu)化生成器和 async 尤其重要。生成器早已得到 V8 的支持,但由于 Crankshaft 控制流的限制而不能進(jìn)一步得到優(yōu)化。async 基本上是生成器的語(yǔ)法糖,因此屬于同一類別。新的編譯器管道利用 Ignition 來(lái)實(shí)現(xiàn) AST,并生成可以轉(zhuǎn)換生成器控制流到簡(jiǎn)單的本地控制流的字節(jié)碼。TurboFan 可以更容易地優(yōu)化所得到的字節(jié)碼,因?yàn)樗恍枰狸P(guān)于生成器控制流的任何具體內(nèi)容,只是如何保存和恢復(fù)函數(shù)的 yield 狀態(tài)。

小組的狀況

我們的短期目標(biāo)是讓效率差距盡快縮減到 2 倍以內(nèi)。我們首先改進(jìn)測(cè)試成績(jī)最差的功能,從 Chrome M54 到 Chrome M58(Canary),我們已經(jīng)成功將測(cè)試速度降了一倍,從 16 降至 8 ,同時(shí) M54 中最差的 19 倍在 M58(Canary)減少到了只有 6 倍。與此同時(shí),我們也大大減少了效率差距的平均和中位數(shù):

可以看到 ES2015+ 和 ES5 正在接近的趨勢(shì)。我們把平均性能提高到了 ES5 的 47% 以上。 以下是自 M54 以來(lái)我們做的一些亮點(diǎn)。

最值得注意的是,我們改進(jìn)了基于迭代的新語(yǔ)言結(jié)構(gòu)的性能,如擴(kuò)展運(yùn)算符,解構(gòu)賦值和 for...of 循環(huán)。例如,使用數(shù)組解構(gòu)賦值

 function fn() {
  var [c] = data;
  return c;
}

和原生的 ES5 賦值語(yǔ)句效率相當(dāng)

 function fn() {
  var c = data[0];
  return c;
}

比 babel 生成的代碼快多了:

 "use strict";

var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

function fn() {
  var _data = data,
      _data2 = _slicedToArray(_data, 1),
      c = _data2[0];

  return c;
}

想了解更多詳細(xì)信息可以在上次慕尼黑 NodeJS 用戶組會(huì)議上查看我們提供的高效 ES2015 演講:

我們致力于繼續(xù)提高 ES2015+ 的性能。如果對(duì)這些細(xì)節(jié)感興趣,請(qǐng)查看 V8 的 ES2015 及其未來(lái)的性能計(jì)劃。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84941.html

相關(guān)文章

  • javascript引擎——V8

    摘要:類將源代碼解釋并構(gòu)建成抽象語(yǔ)法樹,使用類來(lái)創(chuàng)建它們,并使用類來(lái)分配內(nèi)存。類抽象語(yǔ)法樹的訪問(wèn)者類,主要用來(lái)遍歷抽象語(yǔ)法樹。在該函數(shù)中,先使用類來(lái)生成抽象語(yǔ)法樹再使用類來(lái)生成本地代碼。 通過(guò)上一篇文章,我們知道了JavaScript引擎是執(zhí)行JavaScript代碼的程序或解釋器,了解了JavaScript引擎的基本工作原理。我們經(jīng)常聽說(shuō)的JavaScript引擎就是V8引擎,這篇文章我們...

    luoyibu 評(píng)論0 收藏0
  • JavaScript 開發(fā)者所需要知道 V8(一):V8 In NodeJS

    摘要:歡迎來(lái)我的博客閱讀開發(fā)者所需要知道的一是一款擁有自動(dòng)垃圾回收功能的編程語(yǔ)言。它隨著的第一版發(fā)布而發(fā)布以及開源。年月,基金宣布和合并,合并版本在未來(lái)發(fā)布。年月日,官方公布又一個(gè)新的名為的優(yōu)化編譯器,主要提供的新語(yǔ)法,以及提高性能。 歡迎來(lái)我的博客閱讀:「JavaScript 開發(fā)者所需要知道的 V8(一):V8 In NodeJS」 Motivation JavaScript 是一款擁有...

    Lemon_95 評(píng)論0 收藏0
  • Node.js 文檔(ES6功能)

    摘要:所有功能分為三組,用于交付階段和進(jìn)行中的功能認(rèn)為穩(wěn)定的所有交付功能在上默認(rèn)打開,不需要任何類型的運(yùn)行時(shí)標(biāo)志。及更高版本引入的優(yōu)化功能的工作通過(guò)性能計(jì)劃進(jìn)行協(xié)調(diào),團(tuán)隊(duì)收集并協(xié)調(diào)需要改進(jìn)的領(lǐng)域,并設(shè)計(jì)文檔來(lái)解決這些問(wèn)題。 ECMAScript 2015(ES6)及更高版本 Node.js是針對(duì)現(xiàn)代版本的V8構(gòu)建的,通過(guò)與該引擎的最新版本保持同步,我們確保及時(shí)向Node.js開發(fā)人員提供Ja...

    sushi 評(píng)論0 收藏0
  • ES2015 性能及其改進(jìn)方向

    摘要:的新特性往往會(huì)增加代碼的,這些特性卻有助于緩解當(dāng)前的性能危機(jī),尤其像在手機(jī)設(shè)備這樣的新興市場(chǎng)上。聯(lián)合聲明我們短期目標(biāo)是盡快實(shí)現(xiàn)少于倍的性能改善。我們會(huì)繼續(xù)針對(duì)的特性提升其性能。定期發(fā)布高質(zhì)量文章。 作者:Alon Zakai 編譯:胡子大哈 翻譯原文:http://huziketang.com/blog/posts/detail?postId=58d11a9aa6d8a07e449f...

    Aceyclee 評(píng)論0 收藏0
  • V8引擎深入研究目錄貼

    摘要:對(duì)于每個(gè)前端程序員來(lái)講都有一個(gè)終極理想,那就是搞懂引擎是如何工作的。性能經(jīng)過(guò)了兩次飛躍第次飛躍是年發(fā)布,第次則是年的。從去年底開始連載源碼分析,記錄一下自己學(xué)習(xí)源碼的點(diǎn)點(diǎn)滴滴。月星期六晚點(diǎn)和大家一起聊聊引擎前端程序員應(yīng)該懂點(diǎn)知識(shí)講堂。 對(duì)于每個(gè)前端程序員來(lái)講都有一個(gè)終極理想,那就是搞懂 javascript 引擎是如何工作的。 從我的網(wǎng)絡(luò) ID(justjavac)可以看出來(lái),當(dāng)我開始...

    blastz 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<