Зачем


Однажды при разработке компонента графика для веб-браузера мы столкнулись с проблемой обработки последовательностей на JavaScript.

C# разработчики уже много лет пользуются методами расширения для обработки последовательностей. И хотя данная технология не лишена подводных камней, она позволяет во многих случаях избежать утомительного написания рутинного кода по обработке массивов, списков и т.д.

Естественно, хотелось бы иметь аналогичные возможности и на JavaScript.

На данный момент существует немало реализаций LINQ для JavaScript, например, linq.js, $linq. Эти реализации предоставляют широкие возможности, сравнимые с реализацией на C#. Обратной стороной является немалый размер кода, из которого в конкретном приложении может использоваться лишь небольшая часть. Например, нам необходима лишь функция distinct, а мы вынуждены добавлять килобайты кода third-party библиотеки.

Опять же, любопытно разобраться, как же конкретная библиотека работает, а разбирать исходный код большой библиотеки зачастую утомительно. Или в нашем случае у нас уже есть своя библиотека для JavaScript и мы лишь хотим её компактно дополнить функционалом работы с последовательностями.

Насколько пригоден JavaScript для реализации


Определимся с элементами JavaScript, которые необходимы для реализации задуманого. У нас есть массивы, есть лямбда-функции, есть объекты, возможно наследование с некоторыми оговорками. Мы хотим выполнять операции, представленные лямбда-функциями над данными, содержащимися в массивах и эти операции мы хотим сгруппировать в объекте. Всё в порядке.

Попробуем сами


Начнём с определения необходимых сущностей.
Очевидно, что для работы с последовательностями самым базовым объектом является итератор. Всё, что от него нужно, это три метода:
  • moveNext() перемещает указатель на следующий элемент и возвращает true в случае успеха и false, если следующего элемента нет (достигнут конец последовательности);
  • current() возвращает текущий элемент либо null, если такого элемента нет (достигнут конец последовательности);
  • reset() перемещает указатель на первый элемент последовательности.

Значит, нам нужен метод, конструирующий итератор из базовой последовательности (например, из массива JS).

Далее нам нужен объект, который будет содержать набор методов для работы с множествами (where, select и т.д.). Поскольку больше хотелось иметь название, отражающее суть функционала, чем “намекать” на аналоги, было выбрано слово Walkable (суть такой, по элементам которого можно “ходить”/итерироваться). Каждый метод этого объекта должен возвращать тоже объект Walkable, чтобы поддерживать возможность объединять несколько вызовов в одной цепочке (другими словами, чтобы можно было передавать результат исполнения предыдущего метода на вход следующему).

Во-вторых, нам нужен источник данных. Не хотелось бы ограничиваться встроенным массивом JS в качестве единственного источника. Вот здесь нам и пригодится упомянутый выше итератор. Всё, что нам нужно от последовательности, это единственный метод, возвращающий итератор (конечно, каждый раз новый экземпляр, чтобы его можно было использовать, не изменяя состояние других итераторов). На следующем шаге к такому объекту можно “подмешать” методы Walkable и в итоге над результатом можно вызывать любые методы Walkable и каскадировать их в произвольные цепочки.

Проиллюстрируем теорию кодом. Вот метод, создающий объект Walkable из массива JS:

var arrayWalkable = function(arr) {
      var walker = function() { .// внутрення функция-конструктор итератора
        var idx = -1; // состояние итератора
        // далее классические методы итератора
        this.reset = function() { idx = -1; };
        this.moveNext = function() { return (++idx < arr.length); };
        this.current = function() { return (idx < 0 || idx >= arr.length) ? null : arr[idx]; }; 
      };
      // создаём обёртку над массивом, возвращающую итератор
      var walkable = { getWalker: function() { return new walker(); },};
      // расширяем обёртку методами объекта Walkable
      // WAVE.extend - базовая функция нашей библиотеки, при желании можно реализовать/скопировать         
      //свою
      WAVE.extend(walkable, WAVE.Walkable); 
      return walkable;
    }

Далее займёмся собственно объектом Walkable. Он должен содержать методы работы с последовательностями, каждый из которых должен возвращать в свою очеред новый объект Walkable.

Итак, реализуем объект Walkable и самый популярный метод where. Поскольку мы выбрали walkable в качестве названия, то и все методы расширения мы называем с буквы “w”:

wWhere: function(filter) {
                	var srcWalkable = this;
                	var walkable = {
                  	  getWalker: function() {
                      	    var walker = srcWalkable.getWalker();
                    	    return {
                      	      reset: function() { walker.reset(); },
                      	      moveNext: function() {
                        	  while (walker.moveNext()) {
                          	    var has = filter(walker.current());
                          	    if (has) return true;
                        	  }
                        	  return false;
                      	      },
                      	      current: function() { return walker.current(); }
                    	    };
                  	  }  
                	}
                	WAVE.extend(walkable, WAVE.Walkable);
                	return walkable;
    	}, //wWhere

В качестве аргумента для wWhere принимаем функцию filter, которая в свою очередь принимает на вход элемент последовательности и возвращает true или false (включать или нет элемент в результат). Далее запоминаем this в переменной srcWalkable (классический приём в JS).

На следующем шаге по аналогии с вышеописанным методом arrayWalkable определяем базовый объект walkable с ключевым методом getWalker. При каждом вызове получаем новый итератор текущего объекта, чтобы не влиять на другие итераторы. И возвращаем объект.

Затем переопределяем в соответствии с логикой операции where методы итератора:
  • reset: просто вызывает reset источника последовательности (например, это может быть объект, произведённый методом WAVE.arrayWalkable, описанным выше;
  • moveNext: вызывает moveNext источника последовательности, пока не найдёт элемент, удовлетворяющий критерию filter, либо пока не достигнет конца исходной последовательности;
  • current: вызывает current источника последовательности.

Пример использования


В качестве простейших примеров использования можно привести фрагменты юнит-тестов.

Продемонстрируем работу самого итератора и Walkable:

Легко видеть, что такой дизайн позволяет выстраивать произвольные функции, возвращающие Walkable, в цепочки произвольной длинны.

По аналогии с wWhere реализуются остальные функции нашей библиотеки, например, wSelect, wDistinct и т.д.

function() {
          var a = [1, 2, 3, 4, 5]; 

          var aw = WAVE.arrayWalkable(a);

          var walker = aw.getWalker(), i=0;
          while(walker.moveNext()) {
            assertTrue(a[i] === walker.current());
            i++;
          }

          assertFalse(walker.moveNext());
          assertTrue(null === walker.current());
     }

Теперь используем wWhere, выстроив их в цепочку:

function() {
          var a = [1, 2, 3, 4, 5]; 

          var aw = WAVE.arrayWalkable(a);
          var wWhere1 = aw.wWhere(function(e) { return e > 1; });
          var wWhere2 = wWhere1.wWhere(function(e) { return e < 5; });
          var result2 = wWhere2.wToArray();

          for(var i in result2) log(result2[i]);

          assertTrue( 3 === result2.length);
     }

В коде использованы функции-обёртки для тестирование, включённые в wv.js.

Выводы


Реализация собственной LINQ-подобной библиотеки на JavaScript не является сложной задачей и каждый желающий с минимальными знаниями программирования может с ней справиться.

Тем не менее, по нашему опыту, подобная библиотека очень здорово упрощает написание основанной на работе с сериями данных логики, при этом занимая в коде ровно столько места, сколько функций нам от неё необходимо.

Исходный код библиотеки может быть получен тут, юнит-тесты находятся тут.
П.С:
Решил добавить полный список функций Walkable:
wSelect, wSelectMany, wWhere, wAt, wFirst, wFirstIdx, wCount, wDistinct, wConcat, wExcept, wGroup, wGroupIntoObject, wGroupIntoArray, wGroupAggregate, wOrder, wTake, wTakeWhile, wSkip, wAny, wAll, wMin, wMax, wAggregate, wSum, wEqual, wToArray, wEach, wWMA (moving average), wHarmonicFrequencyFilter (наш собственный фильтр, концепция зарекомендовала себя отлично, например, здесь), wConstLinearSampling, wSineGen, wSawGen, wSquareGen, wRandomGen,

Комментарии (72)


  1. Yavanosta
    06.07.2015 17:07
    +3

    1) лично я ни разу не сталкивался в js с необходимостью обработать коллекцию, которой ещё нет целиком, т.к. в JS, по крайней мере в браузере, нет никаких потоковых апи. Вы не можете начать обрабатывать ответ от сервера раньше чем он будет полностью получен, поэтому необходимость работы с коллекциями в «поточном» стиле, с помощью итераторов выглядит немного надуманной. Сделаем из массива итератор, и потом из итератора массив.
    2) с обычными массивами кажется лучшее, по возможности, использовать встроенные функции filter (==Where), some (==Any), every (==All), map (==Select) и другие, потому что они быстрее. Хорошо бы набросать на jsperf тест и сравнить с вашими, но кажется что нативные выйграют. Возможно ваши будут побеждать на очень больших коллекциях, т.к. не создается промежуточных коллекций, но кажется что этот выйгрыш будет только на очень-очень-очень больших массивах.
    3) таких библиотек уже очень много, не совсем ясно зачем делать еще одну.


    1. dxwizard Автор
      06.07.2015 17:30

      1) Пока мы обрабатываем как раз коллекции, ктр. в браузере уже есть. Но это не исключает использование коллекций, ктр. ещё полностью нет, а смастерить конструкцию, ктр. будет возвращать результат несколькими порциями, не составляет принципиальной сложности. В любом случае, спасибо за идею, мы даже как-то не задумывались над таким сценарием использования
      2) а) для обычных массивов и простых операций — возможно. Но если нужна, скажем, агрегация, то встроенные не решат всех проблем.
      б) хотелось иметь реализацию, использующую «консервативные» конструкции JS во избежания всяких пролем с совместимосью
      3) Вы, безусловно, правы насчёт существования множества других похожих библиотек. Однако я объяснил причины своей реализации в самом начале статьи. Могу разве что добавить, что ключевая идея нашего фрэймворка NFX — Unistack, т.е. своё решение от начала до конца, пусть даже это будет напоминать изобретение велосипеда. Наш опыт говорит, что такая философия — самая выгодная в долгосрочной перспективе.


      1. lair
        06.07.2015 17:39
        +3

        для обычных массивов и простых операций — возможно. Но если нужна, скажем, агрегация, то встроенные не решат всех проблем.

        Любая агрегация делается через reduce. Собственно, есть ровно три с половиной операции, необходимых для реализации практически любых операций над множествами данных: reduce, map, filter, mapFlat.

        хотелось иметь реализацию, использующую «консервативные» конструкции JS во избежания всяких пролем с совместимосью

        Ну так полифиллы вам в помощь.


        1. lair
          06.07.2015 17:49
          +2

          mapFlat -> flatMap


        1. itadapter
          06.07.2015 18:16

          да все можно, вопрос только в простоте практического применения
          например тут:
          github.com/aumcode/serbench/blob/master/Source/Serbench/WebViewer/views/OverviewCharts.htm#L79-115


          1. lair
            06.07.2015 18:22

            (Особенно, конечно, поведение Distinct доставляет. Ну да ладно.)

            А чем, скажите, ваши wSelect и wEach проще в применении стандартных map и forEach?


            1. itadapter
              06.07.2015 18:32

              ничем, однако оно даёт универсалность обработки разних данных, например
              как такое сделать?
              github.com/aumcode/nfx/blob/master/Source/NFX.Wave/Templatization/StockContent/Embedded/script/wv.utest.htm#L2726-2771

              уравниваем самплинг
              github.com/aumcode/nfx/blob/master/Source/NFX.Wave/Templatization/StockContent/Embedded/script/wv.utest.htm#L2886-2901


              1. lair
                06.07.2015 18:36
                +1

                Из ваших тестов не понятно, какое именно надо сделать.

                (и да, есть у меня подозрение, что вот для того, что у вас там проглядывается, надо брать Rx)


              1. Yavanosta
                06.07.2015 18:44

                как такое сделать?

                Желательно такое не делать никак. Вы зачем-то вынесли в стандартную библиотеку работы с коллекциями метод который:
                1) кажется делает какую-то достаточно специфичную обработку, которая нужна явно «не каждый день»
                2) работает только с коллекцией определенного формата. Тоесть я могу сделать
                Walkable.fromJs([1,2,3]).wWMA()
                

                И это будет валидный код, только странный, потому что метод wWMA подразумевает конкретный формат коллекции на входе. Такие методы нужно выносить в отдельные библиотеки
                3) очень странно называется и принимает коллекцию имеющую однобуквенные названия.

                Что же касается вашего вопроса, я склонен считать, что можно переписать вашу обработку на стандартных функциях работы с массивами, и она скорее всего будет быстрее вашей.


      1. Yavanosta
        06.07.2015 18:05
        +1

        1) использование итераторов приобретает смысл в основном только при необходимости работы с не загруженными до конца коллекциями, когда их полная загрузка в память тяжела или невозможна (обработать 100тб данных например), либо при комбинировании цепочек обработки, т.к. не нужно создавать промежуточных коллекций. Обрабатывать плоские массивы итераторами выглядит странным, потому что вы платите за сложный доступ к элементу с помощью вызова метода итератора, вместо простой адресации массива, но не получаете за это ничего.

        Чтобы использовать загрузку данных по кусками, у вас метод getNext должен возвращать промис, иначе не понятно что делать итератору, в ситуации когда коллекция ещё не завершена, но её продолжение ещё не доступно, и соответственно все методы должны работать с промисами, и быть асинхронными. Это ещё один большой оверхед который вы заплатите ни за что.

        Итого единственная ситуация где вы возможно выигрываете, это обработка большой коллекции большим количеством последовательных операций. Но такой код лучше переписать, так, чтобы операция были сложные, но мало, с использованием map/reduce, и, кажется, в этой ситуации вы снова проиграете.
        2) а) приведите пожалуйста пример выборки которую нельзя сделать с помощью map\reduce? Вроде бы к ним сводится почти все
        б) более правильно заполифилить методы Array.filter/map/reduce/etc которые уже нативно поддерживаются в большинстве даже мобильных браузеров. Единственный где их нет, это IE <= 8, но его доля уже не так велика (мягко говоря), можно заполифилить.
        3) ваше конечно право, но тратить деньги на то, чтобы переписывать то, что уже давно есть в bower кажется странным. Селекторы вы тоже свои написали или querySelector всетаки используете?


  1. kuber
    06.07.2015 17:17

    На С# запрос выглядит много интересней:
    var result = a.Where(x => x > 1 && x < 5).ToArray();


    1. dxwizard Автор
      06.07.2015 17:32

      Согласен, но, как Вы понимаете, в JS это просто так работать не будет. Была идея с неким промежуточным языков предикатов для Walkable, однако мы решили от неё отказаться в силу несоответствия сложности возможной выгоде.


      1. Zibx
        06.07.2015 17:39
        +1

        Конкретно пример выше идеально реализуется на массивах через .filter.


    1. o_nix
      06.07.2015 17:39
      +3

      linqjs.codeplex.com

      var queryResult2 = Enumerable.From(jsonArray)
          .Where("$.user.id < 200")
          .OrderBy("$.user.screen_name")
          .Select("$.user.screen_name + ':' + $.text")
          .ToArray();
      


      1. xGromMx
        06.07.2015 17:41

        Почему тогда не github.com/Reactive-Extensions/RxJS или подобная библиотека?


        1. lair
          06.07.2015 17:43

          У Reactive философия все-таки другая, с observables/promises еще надо научиться работать надо.


          1. xGromMx
            06.07.2015 17:45

            У Reactive прекрасная филофия, попробоваши раз, уже не остановить =)


            1. lair
              06.07.2015 17:46
              +1

              Ну, вы в этот угол можете свою философию не продавать, тут уже распробовали.


        1. o_nix
          06.07.2015 17:44

          Новедь! это подход к обработке событий. Мне кажется, это немного другое.


      1. kuber
        06.07.2015 17:45

        Ваш код не будет делать тоже, что и код в примере статьи.


        1. o_nix
          06.07.2015 17:49

          Я и не претендовал на работающий код к статье. :)
          Это пример из мануала самого фреймворка, наглядно показывающий возможности, которые вы запросили.


          1. kuber
            06.07.2015 17:56

            Обычно в мануале разработчики ставят самые яркие примеры, чтобы привлечь внимание. Я пользовался этой библиотекой и поверьте там все совсем не так прекрасно.


            1. o_nix
              06.07.2015 18:07

              Будем рады, если распишите pros & cons.


      1. dxwizard Автор
        06.07.2015 17:54

        а если нужно заюзать существующую внешнюю функцию в предикате?


        1. o_nix
          06.07.2015 18:08

          Ну, мне кажется, просто передаёте её аргументом, не?


  1. xGromMx
    06.07.2015 17:36
    +2

    lodash.com можно использовать модульно.


    1. dxwizard Автор
      06.07.2015 17:42
      -1

      не буду спорить, но там как минимум другой стиль.
      + не сочтите параноиком, но что делать, если:
      — это проект перестанет поддерживаться, а нужна будет критическая модификация (придётся либо разбираться в этом коде досконально либо избавляться от него в пользу другого 3rd-party)?
      — какая лицензия в предложенной библиотеке?


      1. xGromMx
        06.07.2015 17:44
        +1

        Там все довольно просто написано, лицензию можете глянуть на github


        1. lair
          06.07.2015 17:54

          На гитхабе лицензия формата «можно все», если я ничего не попутал.


          1. dxwizard Автор
            06.07.2015 18:03

            необязательно, вопрос лицензирования — ещё тот «pain in ass», как-то потратил несколько часов на разбирательство, но всех ответов не получил.
            и даже если «можно всё», то что с поддержкой — непонятно (точнее понятно, что ненадёжно)


            1. lair
              06.07.2015 18:04
              +2

              Что «необязательно»? Вы конкретный текст лицензии уже прочитали, чтобы так говорить?


            1. Yavanosta
              06.07.2015 18:16

              Тоесть вы считаете лучше все самим переписать, вместо того чтобы потратить несколько часов на разбирательство с лицензией?


              1. itadapter
                06.07.2015 18:21

                дело в комплексном подходе.
                Walkable исползуется в 100 мест в разних компонентах огромнои системы.
                Для того чтобы что-то «слепить» пару раз конечно не нужно.

                это как — стоит ли там хонде или ниссану самому делать сидения для машин


                1. Yavanosta
                  06.07.2015 18:30
                  +2

                  Она используется в 100 местах огромной системы, потому что вы так решили, а не потому что она лучше. Так тот факт, что вы её используете в 100 местах вообще не аргумент ни за что. И если уж на то пошло, то underscore используется в гораздо большем количестве мест.

                  Доказательств того, что ваше решение хотябы не хуже вы не представили. В первую очередь интересует производительность.

                  На мой вопрос вы не ответили. Пока я вижу позицию «там какая-то сложная лицензия, мы потратили несколько часов на то, чтобы в ней разобраться, но решили все переписать». Это очень странно и удивительно, потому что на то чтобы переписать, покрыть тестами и документацией, надо гораздо больше нескольких часов, а значит это тупо в разы (скорее даже на порядки) дороже. Очень странный подход, хотелось бы каких-то обоснований ему.

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


                1. lair
                  06.07.2015 18:35

                  это как — стоит ли там хонде или ниссану самому делать сидения для машин

                  Все аналогии врут.

                  The [Honda] Integra Type R comes equipped with Recaro seats, four-piston Brembo front brakes…

                  (Wiki, сайт производителя)


                  1. itadapter
                    06.07.2015 18:45

                    вам ничего не продают, мы делимся опытом.
                    если вы считаете что вас обманули в чем-то, зачем тогда писать комментарии вообше не по теме.
                    вы прекрасно понимаете сравнение с производителями авто и дисскутировать это нет смысла.

                    если вам РЕАЛьНО интересно зачем мы делаем так как мы делаем, задайте конкретние вопросы и ПРОЧИТАЙте внимательно ответ.

                    а так я с вами на 1000% процентов согласен — все ето никому не надо, вообще ничего никому не надо и уэ все есть в тои или инои форме


                    1. lair
                      06.07.2015 18:46
                      -1

                      Да вы уже писали, почему вы так делаете — потому что вы считаете, что знаете как лучше.


                      1. itadapter
                        06.07.2015 18:52

                        посмотрите на это. займет реално 3 минути внимания.

                        github.com/aumcode/serbench

                        я не успел ещо опыбликоват реzултаты — сами их получите на своеи машине

                        там все тесты ПРОТИВ НФХ, там все заточено под других производителей.

                        это реалная работа, понимаете? возмите и запустите. там все будет видно на екране компа.

                        если вам реално интересно. этот тул именно для скептиков, первые — это мы сами.


                        1. lair
                          06.07.2015 18:53

                          А там где-нибудь есть тест «сколько бы мы это писали на lodash/RxJS»?


                        1. Yavanosta
                          06.07.2015 18:57
                          +1

                          Мы тут вроде про LINQ на JS разговариваем, а вы предлагаете, на сколько я понял за 3 минуты, сравить .NET сериализаторы в JSON? Это сейчас к чему вообще?

                          Но если хотите давайте поговорим про них, только выложите пожалуйста какие-нибудь графики сюда, я к сожалению не хочу запускать у себя бинарник непонятного происхождения, да и вообще сижу под убунтой.


                    1. Yavanosta
                      06.07.2015 18:50

                      Да ладно вам, обижаться. Как-то несолидно, честное слово. Нам тут всем РЕАЛЬНО интересно зачем вы это делаете. Но на все вопросы по сути вопроса, вы не отвечаете, и никаких аргументов не приводите, кроме того, что вы считаете что использовать готовые библиотеки опасно, т.к. Not invented here.

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


                      1. itadapter
                        06.07.2015 18:55
                        -1

                        1. lair
                          06.07.2015 18:56

                          Так у вас там, дайте я угадаю, поток событий в реальном времени на самом деле?


                          1. itadapter
                            06.07.2015 18:59

                            yes, server processes steady 100,000 msg/sec using NFX Glue + Erlang.OTP

                            Generates JSON payload which is fed to client via NFX.Wave server, client workls over a buffer of around 5-10K summaries that the user may visually adjust (find harmonics, apply EMA, edd noise etc..) they see it in chart

                            is this the most efficient solution? no it is not. the most efficient one would have been rewriting all in WPF/C# on the client, but it does its job very well.


                            1. lair
                              06.07.2015 19:00
                              -1

                              Так что ж вы RxJS-то не взяли, который для этого заточен (и расширяем любыми операциями, какие вам хочется)?


                          1. dxwizard Автор
                            06.07.2015 19:01

                            строго говоря, js не выполняется на системах реального времени


                        1. Yavanosta
                          06.07.2015 19:01

                          Вы сейчас кому вообще отвечали?

                          Давайте я сделаю еще одну попытку достучаться до вашего сердца.

                          Приведите пожалуйста какой-нибудь аргумент, чем реализация какой-либо обработки массива с помощью walkable лучше чем реализация той же самой обработки на Array.map/reduce/filter?

                          Если хотите, давайте выберем один алгоритм и сравнием на jsPerf вашу реализацию и более нативную?

                          Аргумент в моем понимании это утверждение, а не кусок кода. Например
                          — мы считаем что вот это работает быстрее чем на нативных функциях
                          — мы считаем что так писать код понятнее
                          — whatever else


                          1. itadapter
                            06.07.2015 19:06
                            -2

                            я только за!
                            возмите и сравните наш случай который описан выше (про трайдинг)

                            уверен что у нас будет все медленее а может и нет, насколько — посмотрим
                            однако если вы наидете и порекоммендуете ускорение — бyдем очен признательны


                  1. Yavanosta
                    06.07.2015 18:45

                    Brilliant!


          1. itadapter
            06.07.2015 20:22

            sorry, but it appears that mostly people have no clue what a license means in the context of a «civilized world».
            The OpenSource licenses are very much liable to err when there is dough involved…


            1. lair
              07.07.2015 11:07

              А вы уже ознакомились с конкретной обсуждаемой лицензией, или это так, общее-наболевшее?


      1. mr47
        06.07.2015 20:38
        -1

        Простите меня но сейчас 2015 на дворе есть гитхаб. Лицензия как минимум MIT.

        — это проект перестанет поддерживаться, а нужна будет критическая модификация (придётся либо разбираться в этом коде досконально либо избавляться от него в пользу другого 3rd-party)?

        Это не 3rd-party — это стандарт для разработчиков на JS. В текущий момент lodash и underscore самые популярные библиотеки их применение показывает ваше умение. Кроме того если внимательно следить за гитом 2х этих библиотек люди чтобы сделать PR должны предоставить пачку тестов +JSPerf. Поэтому код в них крайне, крайне быстр и достаточно покрыт тестами. Велосипед выше который — не тестируем, не предсказуем, и крайне опасен для продакшена.

        Как идея для постижения JS вполне себе ничего.


        1. dxwizard Автор
          06.07.2015 20:51
          +1

          >> Это не 3rd-party — это стандарт для разработчиков на JS. В текущий момент lodash и underscore самые популярные библиотеки
          >> применение показывает ваше умение. Кроме того если внимательно следить за гитом 2х этих библиотек люди чтобы сделать PR должны >>предоставить пачку тестов +JSPerf
          как я писал неоднократно и в самой статье, и в комментах, мы избегаем вводить в свой фрэймворк чужой исходный код.
          отдельные библиотеки как таковые могут быть просто великолепны, однако, их совместное использование часто вызывает концептуальные и стилистические несоответсвия и код превращается в мешанину.
          >> Велосипед выше который — не тестируем, не предсказуем, и крайне опасен для продакшена.
          на чём вы основываетесь, говоря, что «велосипед» нетестируем?


          1. mr47
            06.07.2015 21:19

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


            Ага я заметил в вашей чудо библиотеке undefined в одном случае у вас string в одном обьект с этим проблем конечно нет сравнения верные но красотой кода и ее стилистикой даже не пахнет начиная от названий пременых заканчивая названиями функций обработчиков ошибок.

            Перфоманс нулевой если у вас
            for(var i=0; i<name.length; i++)
            ...
            

            Серьезно? Вы знали что в цикле использование name.length это заведомое обращение к обьекту N раз?
            А что нативный forEach и map при некоторых условиях быстрее в разы чем обычный for? ( Особенно заметно на webkita'х ).

            У вас даже стайлгайда нету, о каком стиле вы говорите может об этом ?
            var srcWalkable = this;
            

            и буквально ниже
            var self = this;
            

            Это каша из функций которая писать для нее тесты у меня желания не возникает. Там собраны десяток УЛЬТА полезных функций которые есть в lodash и underscore. Математический аппарат я не оцениваю нет сил и времени разбираться.

            ES2015 Generators и код этой библиотеки можно выкинуть.

            Кроме того существуют вещи которые просто вводят в ступор в JS. Вот пример вам :
            ...
            obj.method();
            ...
            

            и
            (null,obj.method)()
            

            В некоторых случаях это дает прирост почти от ~2% — 10% на webkit'ах но на ~15% медленнее в IE 11. И если это сортировка там 1000000 маркеров по некому критерию то я сделаю так чтобы в одном случае получить прирост на 10% а в другом остаться на текущей производительности.


            1. dxwizard Автор
              06.07.2015 21:36

              >>Ага я заметил в вашей чудо библиотеке undefined в одном случае у вас string в одном обьект с этим проблем конечно нет сравнения >>верные но красотой кода и ее стилистикой даже не пахнет начиная от названий пременых заканчивая названиями функций >>обработчиков ошибок
              не сочтите за грубость, но я иногда затрудняюсь читать Ваши комментарии без знаков препинания )

              >> У вас даже стайлгайда нету, о каком стиле вы говорите может об этом?
              естественно, нету, и, смею надеятся, не будет )

              >>ES2015 Generators и код этой библиотеки можно выкинуть.
              выкидывайте, дорогой mr47, ни в чём себе не отказывайте )


            1. dxwizard Автор
              07.07.2015 19:19

              >> Ага я заметил в вашей чудо библиотеке undefined в одном случае у вас string в одном обьект с этим проблем конечно нет сравнения >> верные но красотой кода и ее стилистикой даже не пахнет начиная от названий пременых заканчивая названиями функций >
              >>обработчиков ошибок.

              Вы не могли бы подсказать, где у нас «undefined» является объектом?


              1. mr47
                07.07.2015 19:53

                Выкидывайте, дорогой mr47, ни в чём себе не отказывайте.
                Денег на нормального фронтендщика нет так бы и сказали.

                Вы не могли бы подсказать, где у нас «undefined» является объектом?

                Вот прямо сейчас откройте консоль и напишите
                var und = "undefined";
                var k = undefined;
                console.log(typeof k===und); // у вас так часто но есть и == (не строгое сравнение)
                

                Такой код будет работать но, всегда есть это «НО»:
                k === und // false
                ....
                ...
                k === undefined // true
                

                Если кто то попробует использовать в вашем коде такое то результат будет плачевен мне правда не понятно о каком таком стиле вы писали в начале статьи.
                И я вас отправлю сразу прямиком к стандарту этого чудного языка javascript

                И это далеко не придел фантазии а если попробовать
                "".split().length // 1
                "".split("").length // 0
                

                И это далеко не самые большие странности…

                Не пишите больше на javascript. Пишите больше но — осмысленно. А лучше наймите хорошего фронтендера/джаваскриптера он вам все объяснит.
                PS: я не буду оценивать уровень вашего текущего фронтендщика и есть он есть вообще, но отсутствие модульности, самой простой системы сборки (grunt, gulp, броколи и прочие) не говоря уже об webpack. Это крайне печально пару лет назад писали вот так вот не зная об AMD, Commonjs и прочего новомодного (imports из es2015).

                Пожелаю вам удачи. Ведь она самое главное :)


                1. dxwizard Автор
                  07.07.2015 21:01

                  >> Денег на нормального фронтендщика нет так бы и сказали.
                  Вы любите считать чужие деньги? )

                  >>>>Вы не могли бы подсказать, где у нас «undefined» является объектом?
                  ответа на заданый вопрос я не получил,

                  >>я не буду оценивать уровень вашего текущего фронтендщика и есть он есть вообще, но отсутствие модульности, самой >>простой системы сборки (grunt, gulp, броколи и прочие) не говоря уже об webpack. Это крайне печально пару лет назад писали >>вот так вот не зная об AMD, Commonjs и прочего новомодного (imports из es2015).
                  собственно, никто и не просил об оценке )


                  1. mr47
                    07.07.2015 21:23

                    ответа на заданый вопрос я не получил
                    И не получите, я же не буду за вас делать вашу работу. Я и так вас бесплатно проконсультировал в вопросах фронтенда на текущий момент.
                    Вы любите считать чужие деньги? )
                    А никто и не считал, я просто констатировал очевидное из вашего кода. И собственно вы же это делали для ультробыстрогосервевера который обрабатывает аж 100000000 запросов в секунду. Странно куда у вас делись средства. Да не суть.
                    собственно, никто и не просил об оценке )
                    Тогда этому не место на хабре.
                    Используйте свой бложек или жжчку.

                    А зачем вы написали об этом?
                    Тем не менее, по нашему опыту, подобная библиотека очень здорово упрощает написание основанной на работе с сериями данных логики, при этом занимая в коде ровно столько места, сколько функций нам от неё необходимо.


                    Ваши логика из 2004 наверное когда не было гита как токового когда не было кучи кода который бери используй. И все стремились писать и собирать свои собственные библиотеки супер функций которые постоянно дополняются и обновляются из проекта в проект.А сейчас 2015 прошу проснуться пока еще не поздно. Клиент конечно как мамонт не вымрет но явно с таким качеством ограничит вас — что и хорошо :)

                    PS: Как один из тех кто пытался достучатся до вас двоих, аккуратно объясняя суть, вводя в современный фронтенд.

                    Желаю вам — удачи.


                    1. dxwizard Автор
                      07.07.2015 22:23

                      >>И не получите, я же не буду за вас делать вашу работу. Я и так вас бесплатно проконсультировал в вопросах фронтенда >>на текущий момент.
                      Вы обвинили нас в том, что не можете подвердить

                      >>Тогда этому не место на хабре.
                      >>Используйте свой бложек или жжчку.
                      Теперь буду знать, что нужно обязательно у Вас спросить разрешения перед публикацией
                      Написал для тех людей, кому интересно разобраться, как написать подобный функционал с нуля

                      >>Ваши логика из 2004 наверное когда не было гита как токового когда не было кучи кода который бери используй. И все >>стремились писать и собирать свои собственные библиотеки супер функций которые постоянно дополняются и >>обновляются из проекта в проект.А сейчас 2015 прошу проснуться пока еще не поздно. Клиент конечно как мамонт не >>вымрет но явно с таким качеством ограничит вас — что и хорошо :)
                      Вы думаете, что логика так сильно меняется за 11 лет? )
                      По-моему, кто хочет, использует готовые компоненты, кто не хочет, не использует.
                      Повторюсь, статья и была адресована тем, кто хочет сделать свои.

                      >>Желаю вам — удачи.
                      Спасибо, Вам абсолютно искренне того же


                      1. lair
                        07.07.2015 23:43

                        Вы думаете, что логика так сильно меняется за 11 лет? )

                        Вообще — да. По крайней мере, ей лучше бы меняться, потому что индустрия меняется.


                        1. itadapter
                          08.07.2015 01:24

                          как по мне — так не поменялось ничего вообще со времен кнута и жекстры.
                          да компутеры стали в 1000 раз быстрее+SSD+networking етц. однако как хранили 10,000,000 записеи в 1997 годы в оракле
                          так и сегодня (vertical software) — тол'ко сегодня все виснет и сплошине ошибки :) — конечно мне и всем осталним программистам это
                          выгодно когда береш /hour но когда работаеш на себя — совсем другая картина.

                          а впрочем мало что изменилось — тот кто грамотный мыслитель сможет написать в 2015 хоть на Борланд ТП хоть на Руби —

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


                          1. lair
                            08.07.2015 11:05

                            однако как хранили 10,000,000 записеи в 1997 годы в оракле так и сегодня

                            Сегодня десять миллионов записей — это рутина. Я за несколько месяцев написал систему, которая (на одном сервере, без особых оптимизаций) порождает порядка миллиона записей в месяц, если не быстрее. В соседнем посте люди обрабатывают миллион записей в минуту. И это все — рутина.

                            например вы набросились на г-на визарда за его статию — а ведь это реально круто работает в массе прикладных задач.

                            Да много, что круто работает в массе прикладных задач, только вынося это решение на публику, надо быть готовым услышать, что есть решения лучше. Какие? Вам показали.


        1. itadapter
          06.07.2015 21:18

          how many times have you owned a software company in the US and been sued for licensing violations?
          MIT = means nothing
          when you sell your IP, lawyers do a due diligence on you, that is when EVERY LIBRARY that you use is going to open
          a potential legal case, and transform to $10-20K of hiring legal counsel with technical background to deliver the statement of IP validity


          1. mr47
            06.07.2015 21:22

            Просто оставлю это здесь.

            THE SOFTWARE IS PROVIDED «AS IS», WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


            1. itadapter
              06.07.2015 21:27

              this means absolutely nothing. and obviously you have no background in law interpretation.

              funny, Serge Alaynikov who has just been acquitted today after 4 years of legal battle,
              — acquitted for the 2nd time — as this VIOLATES the constitution and double jeopardy law.

              he has been sued EXACTLY for this — he posted code under MIT and Apache while at Goldman,
              the code that HAS BEEN opensource for 10 years — he spent in jail almost a year. go google him up bro


              1. itadapter
                06.07.2015 21:30

                1. mr47
                  06.07.2015 21:48

                  Эта история идиотизм более того он же работал в банковской системе. Вот скажите почему компания joynet не подала в суд на контребьюторов io.js?

                  Или почему гугл пользуется jquery как и тысячи сайтов совершенно бесплатно? Причем я не слышал о громких делах связных с jquery.

                  Это идиомы, 20000$ в банковских системах — ничто. Я не собираюсь с вами спорить о лицензиях и об открытом ПО.

                  И стоило бы написать на языке ресурса.


                  1. itadapter
                    06.07.2015 22:06

                    people get sued daily. you just don't know about it.
                    the moment you start making money — you will get sued. This is how society works.

                    I have personally sold code on numerous occasions, every time whoever buys your code will execute a complete investigation
                    what they are buying. I agree with you — this is laughable, but it is how it works.
                    An average technical attorney charges $500/hr in New York.
                    To read your code base (even if it uses JQuery, Angular, MySQL) — they will charge at the very least 10 hrs investigation +
                    2 hrs admin time, so here you are at $6,000 bill.

                    The case of Serge — I know personally, our common friend was in court. The accusations that have been set — are completely contradictory to what the LICENSING terms of EXISTING code showed, the code existed BEFORE Goldman. The case was 100% fabricated form day 1.

                    This is just an illustration. I was trying to explain that licensing does not really protect companies when someone wants to push them


                    1. mr47
                      06.07.2015 22:16

                      Сергея скорей всего посадили за типичную лицензию MIT. Но опять же тут вопрос к юристам. А вообще лучше использовать уже готовые лицензии больших проектов например .

                      Facebook много платит своим юристам чтобы подобного не было. Просто иногда стоит подумать дважды когда работаешь на людей которые орудуют миллионами — особенно банки.


                    1. lair
                      07.07.2015 11:13

                      Oh, srsly.

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

                      Во-вторых… я несколько раз продавал и покупал код, иногда у вполне себе международных компаний. Никакого complete investigation не было.
                      В-третьих, если вам верить, то этот ваш поверенный все равно будет читать ваш код, вне зависимости от того, используете вы сторонние библиотеки, или нет. Так почему бы их не использовать?

                      В одном вы правы: сам по себе факт лицензии не защищает вас, если кто-то хочет до вас докопаться, и чем крупнее тот, кто до вас докапывается, тем вам тяжелее. Но в этом случае вас вообще ничего не защищает, кроме адвоката. Продали свой и исключительно свой код? Получите иск за его повторную продажу (или несанкционированное включение)


  1. mr47
    06.07.2015 20:24
    +1

    Вопрос зачем, когда есть RxJS и подобные, на крайний случай underscore/lodash сойдет.

    (underscore)

    _.chain([1,2,3,1])
      .filter(function(i){
         return i>2
      })
      .value();
    


    А если уже совсем сложные вещи и концепция Rx/Promise/callback-hell не подходит GraphQL или подобные вещи вам в помощь.

    Хотя по большому счету в ES2015 есть и генераторы/интераторы и прочие прелести зачем изобретать?

    (Не относится к автору.)

    PS: Не тормози babel-ни!