Coffeescript быстрее, чем JavaScript? - PullRequest
9 голосов
/ 28 января 2012

Javascript есть везде, и, на мой взгляд, он постоянно приобретает все большее значение.Большинство программистов согласны с тем, что, хотя сам Javascript ужасен, его «территория», несомненно, впечатляет.Благодаря возможностям HTML5 и скорости современных браузеров развертывание приложения через Javascript является интересным вариантом: оно, вероятно, настолько кроссплатформенное, насколько это возможно.

Естественным результатом являются кросс-компиляторы.Преобладающим является, вероятно, GWT, но есть несколько других вариантов.Мой фаворит - Coffeescript, так как он добавляет только тонкий слой поверх Javascript и гораздо более «легкий», чем, например, GWT.

Есть только одна вещь, которая меня беспокоит: хотя мой проект довольно небольшой, производительность всегдабыла важной темой.Вот цитата

GWT SDK предоставляет набор основных Java API и виджетов.Это позволяет вам писать AJAX-приложения на Java, а затем компилировать исходный код в высокооптимизированный JavaScript

Также оптимизирован Coffeescript?Поскольку Coffeescript, похоже, активно использует необычные функции Javascript, я беспокоюсь о том, как их производительность сравнивается.

У вас есть проблемы со скоростью, связанной с Coffeescript?Знаете ли вы хорошее сравнение производительности?

Ответы [ 5 ]

37 голосов
/ 30 сентября 2012

Извините за возрождение старой темы, но она касалась и меня.Я решил провести небольшой тест, и один из самых простых тестов производительности, которые я знаю, - это записать последовательные значения в массив, память расходуется привычным образом по мере роста массива, и циклы for достаточно распространены в реальной жизни, чтобы их можно было рассмотретьрелевантный.

После пары красных сельдей я нахожу, что самый простой метод coffeescript - это:

newway = -> [0..1000000]
# simpler and quicker than the example from http://coffeescript.org/#loops
# countdown = (num for num in [10..1])

Это использует замыкание и возвращает массив как результат.Мой эквивалент таков:

function oldway()
{
    var a = [];
    for (var i = 0; i <= 1000000; i++)
        a[i] = i;
    return a;
}

Как вы можете видеть, результат такой же, и он тоже увеличивает массив.Затем я профилировал в хроме 100 раз каждый и усреднял.

newway() | 78.5ms
oldway() | 49.9ms

Coffeescript на 78% медленнее.Я опровергаю, что «CoffeeScript, который вы пишете, работает так же быстро (и часто быстрее), как JS, который вы написали бы» ( Джереми Ашкенас )


Приложение: ятакже с подозрением относится к распространенному мнению, что «в JS всегда есть эквивалент один к одному».Я попытался воссоздать свой собственный код следующим образом:

badway = ->
    a = []
    for i in [1..1000000]
        a[i] = i
    return a

Несмотря на сходство, он все же оказался на 7% медленнее, потому что он добавляет дополнительные проверки для направления (увеличение или уменьшение), что означает, что это не прямой перевод.

23 голосов
/ 24 мая 2013

Все это довольно интересно, и есть одна правда: кофейный скрипт не может работать быстрее, чем полностью оптимизированный javascript.

Тем не менее, поскольку кофейный скрипт генерирует javascript. Есть способы, чтобы это стоило того. К сожалению, это еще не так.

Давайте рассмотрим пример:

new_way = -> [0..1000000]
new_way()

Это компилируется с помощью кофейного скрипта 1.6.2

// Generated by CoffeeScript 1.6.2
(function() {
  var new_way;

  new_way = function() {
    var _i, _results;

    return (function() {
      _results = [];
      for (_i = 0; _i <= 1000000; _i++){ _results.push(_i); }
      return _results;
    }).apply(this);
  };

  new_way();

}).call(this);

И код, предоставленный clockworkgeek, -

function oldway()
{
    var a = [];
    for (var i = 0; i <= 1000000; i++)
        a[i] = i;
    return a;
}
oldway()

Но поскольку кофейный скрипт скрывает функцию внутри области видимости, мы должны сделать это и для javascript. Мы не хотим polute окно правильно?

(function() {
    function oldway()
    {
        var a = [];
        for (var i = 0; i <= 1000000; i++)
            a[i] = i;
        return a;
    }
    oldway()
}).call(this);

Так что здесь у нас есть код, который делает то же самое на самом деле. А потом мы бы хотели пару раз протестировать обе версии.

Сценарий кофе

for i in [0..100]
    new_way = -> [0..1000000]
    new_way()

Сгенерировал JS, и вы можете спросить себя, что там происходит ??? Он создает i и _i по любой причине. Мне понятно из этих двух, нужен только один.

// Generated by CoffeeScript 1.6.2
(function() {
  var i, new_way, _i;

  for (i = _i = 0; _i <= 100; i = ++_i) {
    new_way = function() {
      var _j, _results;

      return (function() {
        _results = [];
        for (_j = 0; _j <= 1000000; _j++){ _results.push(_j); }
        return _results;
      }).apply(this);
    };
    new_way();
  }

}).call(this);

Итак, теперь мы собираемся обновить наш Javascript.

(function() {
    function oldway()
    {
        var a = [];
        for (var i = 0; i <= 1000000; i++)
            a[i] = i;
        return a;
    }

    var _i;

    for(_i=0; _i <= 100; ++_i) {
        oldway()
    }
}).call(this);

Итак, результаты:

time coffee test.coffee

real    0m5.647s
user    0m0.016s
sys     0m0.076s

time node test.js

real    0m5.479s
user    0m0.000s
sys     0m0.000s

JS занимает

time node test2.js

real    0m5.904s
user    0m0.000s
sys     0m0.000s

Так что вы можете спросить себя ... что, черт возьми, сценарий кофе быстрее ??? а затем вы посмотрите на код и спросите себя ... так что давайте попробуем это исправить!

(function() {
    function oldway()
    {
        var a = [];
        for (var i = 0; i <= 1000000; i++)
            a.push(i);
        return a;
    }

    var _i;

    for(_i=0; _i <= 100; ++_i) {
        oldway()
    }
}).call(this);

Затем мы сделаем небольшое исправление к сценарию JS и изменим a[i] = i на a.push(i) А затем попробуем еще раз ... и затем BOOM

time node test2.js

real    0m5.330s
user    0m0.000s
sys     0m0.000s

Это небольшое изменение сделало его быстрее, чем наш CoffeeScript. Теперь давайте посмотрим на сгенерированный CoffeeScript ... и удалим эти двойные переменные ...

к этому:

// Generated by CoffeeScript 1.6.2
(function() {
  var i, new_way;

  for (i = 0; i <= 100; ++i) {
    new_way = function() {
      var _j, _results;

      return (function() {
        _results = [];
        for (_j = 0; _j <= 1000000; _j++){ _results.push(_j); }
        return _results;
      }).apply(this);
    };
    new_way();
  }

}).call(this);

и БУМ

time node test.js

real    0m5.373s
user    0m0.000s
sys     0m0.000s

Что я пытаюсь сказать, так это то, что использование более высокого языка имеет большие преимущества. Сгенерированный CoffeeScript не был оптимизирован. Но это было не так далеко от чистого кода JS. Оптимизация кода, которую clockworkgeek пытался использовать с непосредственным использованием index вместо push, на самом деле, казалось, имела неприятные последствия и работала медленнее, чем сгенерированный coffeescript.

Правда в том, что такого рода оптимизацию трудно найти и исправить. С другой стороны, от версии к версии, coffeescript может генерировать оптимизированный js-код для текущего браузера или интерпретаторов. CoffeeScript останется неизменным, но может быть сгенерирован снова, чтобы ускорить процесс.

Если вы пишете прямо в javascript, теперь есть способ действительно оптимизировать код так же, как и при использовании реального компилятора.

Другая интересная часть заключается в том, что однажды CoffeeScript или другие генераторы javascript могут быть использованы для анализа кода (например, jslint) и удаления частей кода, где некоторые переменные не нужны ... Компилировать функции по-разному с разными аргументами ускорить вещи, когда некоторые переменные не нужны. Если у вас есть purejs, вам следует ожидать, что есть JIT-компилятор, который будет правильно выполнять свою работу, и это хорошо для coffeescript.

Например, я мог бы оптимизировать сценарий кофе в последний раз, удалив new_way = (function... из цикла for. Один умный программист знает, что единственное, что здесь происходит, - это повторное включение функции в каждом цикле, которая не меняет переменную. Функция создается в области видимости функции и не воссоздается в каждом цикле. Тем не менее, это не должно сильно измениться ...

time node test.js

real    0m5.363s
user    0m0.015s
sys     0m0.000s

Так что это в значительной степени так.

11 голосов
/ 28 января 2012

Краткий ответ: Нет .

CoffeeScript генерирует JavaScript, поэтому его максимально возможная скорость равна скорости JavaScript.Но хотя вы можете оптимизировать код js на low-level (да, это звучит иронично) и получить некоторое повышение производительности - с CoffeeScript вы не сможете этого сделать.Ваша проблема при выборе CS вместо JS, поскольку для большинства задач разница незначительна.

8 голосов
/ 28 января 2012

Coffescript компилируется непосредственно в JavaScript, что означает, что в JS всегда есть эквивалент один к одному для любого источника Coffeescript.В этом нет ничего необычного.Повышение производительности может быть достигнуто за счет оптимизации, например, благодаря тому, что Coffescript сохраняет длину массива в отдельной переменной в цикле for вместо того, чтобы запрашивать ее в каждой итерации.Но это должно быть распространенной практикой и в JavaScript, просто он не поддерживается самим языком.

1 голос
/ 23 декабря 2015

Я хочу добавить что-нибудь к ответу Лоика Фора-Лакруа ...

Кажется, вы печатали только времена одного браузера. И, кстати, «x.push (i)» не быстрее, чем «x [i] = i» в соответствии с jsperf: https://jsperf.com/array-direct-assignment-vs-push/130

Chrome:  push => 79,491  ops/s; direct assignment => 3,815,588 ops/s;
IE Edge: push => 358,036 ops/s; direct assignment => 7,047,523 ops/s;
Firefox: push => 67,123  ops/s; direct assignment => 206,444   ops/s;

Еще один момент -> x.call (this) и x.apply (this) ... Я не вижу никакой причины для производительности. Даже jsperf подтверждает это: http://jsperf.com/call-apply-segu/18

Chrome: 
direct call => 47,579,486 ops/s; x.call => 45,239,029 ops/s; x.apply => 15,036,387 ops/s;
IE Edge: 
direct call => 113,210,261 ops/s; x.call => 17,771,762 ops/s; x.apply => 6,550,769 ops/s;
Firefox:
direct call => 780,255,612 ops/s; x.call => 76,210,019 ops/s; x.apply => 2,559,295 ops/s;

Сначала упомяните - я использовал настоящие Браузеры.

Во-вторых, я расширил тест с помощью цикла for, потому что при одном вызове тест должен быть коротким ...

Последнее, но не менее важное: теперь тесты для всех браузеров выглядят следующим образом:


Здесь я использовал CoffeeScript 1.10.0 (скомпилированный с тем же кодом, который указан в его ответе)

console.time('coffee');// added manually
(function() {
  var new_way;

  new_way = function() {
    var i, results;
    return (function() {
      results = [];
      for (i = 0; i <= 1000000; i++){ results.push(i); }
      return results;
    }).apply(this);
  };

  // manually added on both
  var i;
  for(i = 0; i != 10; i++)
  {
    new_way();
  }

}).call(this);
console.timeEnd('coffee');// added manually

Теперь Javascript

console.time('js');
(function() {

  function old_way()
  {
    var i = 0, results = [];
    return (function()
    {
      for (i = 0; i <= 1000000; i++)
      {
        results[i] = i;
      }
      return results;
    })();// replaced apply
  }

  var i;
  for(i = 0; i != 10; i++)
  {
    old_way();
  }

})();// replaced call
console.timeEnd('js');

Предельное значение цикла for низкое, потому что, если оно будет выше, это будет довольно медленное тестирование (10 * 1000000 вызовов) ...

Результаты

Chrome:  coffee: 305.000ms;   js: 258.000ms;
IE Edge: coffee: 5.944,281ms; js: 3.517,72ms;
Firefox: coffee: 174.23ms;    js: 159.55ms;

Здесь я должен упомянуть, что не всегда кофе был самым медленным в этом тесте. Вы можете убедиться в этом, протестировав эти коды в Firefox.

Мой окончательный ответ:

Сначала скажу - я не очень знаком с coffeescript, но я изучил его, потому что я использую Atom Editor и хотел попробовать собрать свой первый пакет там, но вернулся к Javascript ... Так что, если что-то не так, поправьте меня.

С помощью coffeescript вы можете писать меньше кода, но если речь идет об оптимизации, код становится тяжелым. Мое собственное мнение -> Я не вижу никакой так называемой "продуктивности" в этом языке кофемописи ...

Чтобы вернуться к выступлениям :: Наиболее часто используемым браузером является браузер Chrome (src: w3schools.com/browsers/browsers_stats.asp) с 60%, и мои тесты также показали, что набранный вручную Javascript работает немного быстрее Coffeescript (кроме IE ... - намного быстрее). Я бы порекомендовал Coffeescript для небольших проектов, но если никто не возражает, оставайтесь на том языке, который вам нравится.

...