国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

ES2015 的高性能及其改進(jìn)方向

Aceyclee / 1426人閱讀

摘要:的新特性往往會(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=58d11a9aa6d8a07e449fdd2a

英文原文:High-performance ES2015 and beyond

轉(zhuǎn)載請(qǐng)注明出處,保留原文鏈接以及作者信息

過(guò)去幾個(gè)月 V8 團(tuán)隊(duì)聚焦于提升新增的 ES2015 的一些性能、提升最近一些其他 JavaScript 新特性的性能,使其能夠達(dá)到或超越相應(yīng)的 ES5 的性能。

出發(fā)點(diǎn)

在我們討論這些不同的改進(jìn)之前,要先了解在當(dāng)前的 Web 開(kāi)發(fā)中,已經(jīng)有了廣為使用的 Babel 作為編譯器,為什么還要考慮 ES2015+ 的性能問(wèn)題:

首先,有一些新的 ES2015 特性是只有 polyfill 時(shí)需要的。例如 Object.assign 函數(shù)。當(dāng) Babel 轉(zhuǎn)譯 “object spread property” 的時(shí)候(在 React 和 Redux 中經(jīng)常碰到),就會(huì)依賴(lài) Object.assign 來(lái)替代 ES5 中相應(yīng)的函數(shù)(如果VM環(huán)境支持的話(huà))。

polyfill ES2015 的新特性往往會(huì)增加代碼的 size,這些 ES2015 特性卻有助于緩解當(dāng)前的 web 性能危機(jī),尤其像在手機(jī)設(shè)備這樣的新興市場(chǎng)上。在這樣一種情況下,代碼的解析和的成本將會(huì)很高。

最后,客戶(hù)端的 JavaScript 運(yùn)行環(huán)境只是依賴(lài)于 V8 引擎的環(huán)境之一,還有服務(wù)端的 Node.js 應(yīng)用和工具等,它們都不需要轉(zhuǎn)譯成 ES5 代碼,而直接使用最新的 V8 版本就可以使用這些新特性了。

一起來(lái)看一下下面這段 Redux 文檔中的代碼:

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

有兩個(gè)地方需要轉(zhuǎn)譯:默認(rèn)參數(shù) statestate 作為實(shí)例化對(duì)象進(jìn)行返回。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;
  }
}

假設(shè) Object.assign 要比用 Babel polyfill 生成的代碼要慢一個(gè)數(shù)量級(jí)。這樣的情況下,要將一個(gè)本不支持 Object.assign 的瀏覽器優(yōu)化到使它具有 ES2015 能力,會(huì)引起很?chē)?yán)重的性能問(wèn)題。

這個(gè)例子同時(shí)也指出了轉(zhuǎn)譯的另一個(gè)缺點(diǎn):轉(zhuǎn)譯生成的代碼,要比直接用 ES2015+ 寫(xiě)的代碼體積更大。在上面的例子中,源代碼有 203 個(gè)字符(gzip 壓縮后有 176 字節(jié)),而轉(zhuǎn)譯生成的代碼有 588 個(gè)字符(gzip 壓縮后有 367 字節(jié))。代碼大小是原來(lái)的兩倍。下面來(lái)看關(guān)于 “JavaScript 異步迭代器”的一個(gè)例子:

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

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

Babel 轉(zhuǎn)譯這段 187 個(gè)字符(gzip 壓縮后 150 字節(jié)),會(huì)生成一段有 2987 個(gè)字符(gzip 壓縮后 971 字節(jié))的 ES5 代碼,這還不包括再生器運(yùn)行時(shí)需要加載的額外依賴(lài):

"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);
  };
}();

這段代碼的大小是原來(lái)的 6.5 倍,也就是說(shuō)增長(zhǎng)了 650% (生成的 _asyncGenerator 函數(shù)也可能被共享,不過(guò)這依賴(lài)于你如何打包你的代碼。如果被共享的話(huà),多個(gè)異步迭代器共用會(huì)分?jǐn)偞a大小帶來(lái)的成本)。我們認(rèn)為長(zhǎng)遠(yuǎn)來(lái)看一直通過(guò)轉(zhuǎn)譯的方式來(lái)支持 ES5 是不可行的,代碼 size 的增加不僅僅會(huì)使下載的時(shí)間變長(zhǎng),而且也會(huì)增加解析和編譯的開(kāi)銷(xiāo)。如果我們想要徹底改善頁(yè)面加載速度,和移動(dòng)互聯(lián)網(wǎng)應(yīng)用的反應(yīng)速度(尤其在手機(jī)設(shè)備上),那么一定要鼓勵(lì)開(kāi)發(fā)者使用 ES2015+ 來(lái)開(kāi)發(fā),而不是開(kāi)發(fā)完以后轉(zhuǎn)譯成 ES5。對(duì)于不支持 ES2015 的舊瀏覽器,只有給它們完全轉(zhuǎn)譯以后的代碼去執(zhí)行了,而對(duì)于 VM 系統(tǒng),上面所說(shuō)的這個(gè)愿景也要求我們不斷地提升 ES2015 的性能。

評(píng)估方法

正如上面所說(shuō)的,ES2015+ 自身的絕對(duì)性能現(xiàn)在已經(jīng)不是關(guān)鍵了。當(dāng)前的關(guān)鍵是首先一定要確保 ES2015+ 的性能要比純 ES5 高,第二更重要的是一定要比用 Babel 轉(zhuǎn)譯以后的版本性能高。目前已經(jīng)有了一個(gè)由 Kevin Decker 開(kāi)發(fā)的 six-speed 項(xiàng)目,這個(gè)項(xiàng)目多多少少實(shí)現(xiàn)了我們的需求:ES2015 特性 vs 純 ES5 vs 轉(zhuǎn)譯生成代碼三者之間的比較。

因此我們現(xiàn)在把提升相對(duì)性能作為我們做 ES2015+ 性能提升的基礎(chǔ)。首先將會(huì)把注意力聚焦于那些最嚴(yán)重的問(wèn)題上,即上面圖中所列出的,從純 ES5 所對(duì)應(yīng)的 ES2015+ 版本性能下降 2 倍的那些項(xiàng)。之所以這么說(shuō)是因?yàn)橛袀€(gè)前提假設(shè),假設(shè)純 ES5 的版本至少會(huì)和相應(yīng) Babel 生成的版本速度一樣快。

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

以前版本的 V8 優(yōu)化像 ES2015+ 這樣的語(yǔ)言是比較困難的。比如想要加一個(gè)異常處理(即 try/chtch/finally)到 Crankshaft (V8 以前版本的優(yōu)化編譯器)是不可能的。就是說(shuō)以 V8 的能力去優(yōu)化 ES6 中的 for...of (這里面隱含有 finally 語(yǔ)句)都是有問(wèn)題的。Crankshaft 在增加新的語(yǔ)言特性到編譯器方面有很多局限性和實(shí)現(xiàn)的復(fù)雜性,這就使得 V8 框架的更新優(yōu)化速度很難跟得上 ES 標(biāo)準(zhǔn)化的速度。拖慢了 V8 發(fā)展的節(jié)奏。

幸運(yùn)的是,lgnition 和 TurboFan (V8 的新版解釋器和編譯器)在設(shè)計(jì)之初就考慮支持整個(gè) JavaScript 語(yǔ)言體系。包括先進(jìn)的控制流、異常處理、最近的 for...of 特性和 ES2015 的重構(gòu)等。lgnition 和 TurboFan 的密集組合架構(gòu)使得對(duì)于新特性的整體優(yōu)化和增量式優(yōu)化成為可能。

許多我們已經(jīng)在現(xiàn)代語(yǔ)言特性上所取得的成功只有在 lgnition/TurboFan 上才可能實(shí)現(xiàn)。 lgnition/TurboFan 在優(yōu)化生成器和異步函數(shù)方面的設(shè)計(jì)尤其關(guān)鍵。V8 一直以來(lái)都支持生成器,但是由于 Crankshaft 的限制,對(duì)其優(yōu)化會(huì)極其受限。新的編譯器利用 lgnition 生成字節(jié)碼,這可以使復(fù)雜的生成器控制流轉(zhuǎn)化為簡(jiǎn)單的本地字節(jié)控制流。TurboFan 也可以更容易實(shí)現(xiàn)基于字節(jié)流的優(yōu)化,因?yàn)樗灰郎善骺刂屏鞯奶厥饧?xì)節(jié),只需要知道如何保存和恢復(fù)函數(shù)聲明就可以了。

聯(lián)合聲明

我們短期目標(biāo)是盡快實(shí)現(xiàn)少于 2 倍的性能改善。首先從最差情況的實(shí)驗(yàn)開(kāi)始,從 Chrome M54 到 Chrome M58 我們成功的把慢于 2 倍的測(cè)試集從 16 個(gè)降到了 8 個(gè)。同時(shí)也顯著地使緩慢程度的中位數(shù)和平均數(shù)得以降低。

從下圖中我們可以清晰地看到變化趨勢(shì),已經(jīng)實(shí)現(xiàn)了平均性能超過(guò)了 ES5 大概 47%,這里列出的是在 M54 上的一些典型數(shù)據(jù)。

另外我們顯著提高了基于迭代的新語(yǔ)言的性能,例如傳遞操作符和 for...of 循環(huán)等。下面是一個(gè)數(shù)組的重構(gòu)情況:

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

比純 ES5 版本還要快。ES5:

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

比 Babel 生成的代碼要快的更多。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;
}

你可以到“高速 ES2015” 來(lái)了解更多細(xì)節(jié)的信息。下面這里是我們?cè)?2017 年 1 月 12 日發(fā)出的視頻連接。

我們會(huì)繼續(xù)針對(duì) ES2015+ 的特性提升其性能。如果你對(duì)這一問(wèn)題感興趣,請(qǐng)看我們 V8 的“ES2015 and beyond performance plan。

如果大家對(duì)文章感興趣,歡迎關(guān)注我的知乎專(zhuān)欄-前端大哈。定期發(fā)布高質(zhì)量文章。

我最近正在寫(xiě)一本《React.js 小書(shū)》,對(duì) React.js 感興趣的童鞋,歡迎指點(diǎn)。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/86921.html

相關(guān)文章

  • js技術(shù) - 收藏集 - 掘金

    摘要:還記得剛開(kāi)始學(xué)習(xí)的時(shí)候,內(nèi)存管理前端掘金作為一門(mén)高級(jí)語(yǔ)言,并不像低級(jí)語(yǔ)言那樣擁有對(duì)內(nèi)存的完全掌控。第三方庫(kù)的行代碼內(nèi)實(shí)現(xiàn)一個(gè)前端掘金前言本文會(huì)教你如何在行代碼內(nèi),不依賴(lài)任何第三方的庫(kù),用純實(shí)現(xiàn)一個(gè)。 (譯) 如何使用 JavaScript 構(gòu)建響應(yīng)式引擎 —— Part 1:可觀察的對(duì)象 - 掘金原文地址:How to build a reactive engine in JavaSc...

    Guakin_Huang 評(píng)論0 收藏0
  • js技術(shù) - 收藏集 - 掘金

    摘要:還記得剛開(kāi)始學(xué)習(xí)的時(shí)候,內(nèi)存管理前端掘金作為一門(mén)高級(jí)語(yǔ)言,并不像低級(jí)語(yǔ)言那樣擁有對(duì)內(nèi)存的完全掌控。第三方庫(kù)的行代碼內(nèi)實(shí)現(xiàn)一個(gè)前端掘金前言本文會(huì)教你如何在行代碼內(nèi),不依賴(lài)任何第三方的庫(kù),用純實(shí)現(xiàn)一個(gè)。 (譯) 如何使用 JavaScript 構(gòu)建響應(yīng)式引擎 —— Part 1:可觀察的對(duì)象 - 掘金原文地址:How to build a reactive engine in JavaSc...

    zhou_you 評(píng)論0 收藏0
  • V8 JavaScript 引擎:性能 ES2015+

    摘要:最后,客戶(hù)端只是依賴(lài)于引擎的環(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.blo...

    songze 評(píng)論0 收藏0
  • JS筆記

    摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。異步編程入門(mén)的全稱(chēng)是前端經(jīng)典面試題從輸入到頁(yè)面加載發(fā)生了什么這是一篇開(kāi)發(fā)的科普類(lèi)文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門(mén)教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...

    rottengeek 評(píng)論0 收藏0
  • 「不良視頻」如何消滅?她手把手教你走出第一步

    摘要:嚴(yán)肅的開(kāi)場(chǎng)白故事要從深度學(xué)習(xí)說(shuō)起。本文從視頻分類(lèi)的角度,對(duì)深度學(xué)習(xí)在該方向上的算法進(jìn)行總結(jié)。數(shù)據(jù)集熟悉深度學(xué)習(xí)的朋友們應(yīng)該清楚,深度學(xué)習(xí)是一門(mén)數(shù)據(jù)驅(qū)動(dòng)的技術(shù),因此數(shù)據(jù)集對(duì)于算法的研究起著非常重要的作用。是一個(gè)比較成功的傳統(tǒng)方法與深度學(xué)習(xí)算 showImg(https://segmentfault.com/img/bV7hQP?w=900&h=330); 不嚴(yán)肅的開(kāi)場(chǎng)白 視頻社交已經(jīng)成為...

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

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

0條評(píng)論

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