Pull to refresh

Sausage.js — библиотека для превращения любого кода в цепочку вызовов

Reading time 4 min
Views 1.5K
Я думаю каждый, кто хотя бы раз сталкивался с Canvas в встречал на своем пути одну не крайне не удобную вещь. При работе с Canvas для изменения любого параметра контекста или вызова метода, приходится обращаться сперва к контексту, а потом к методу/свойству — это очень напрягает.

Всегда хочется вот такой код:
var ctx = document.querySelectorAll('canvas')[0].getContext('2d');
ctx.fillStyle = '#eee';
ctx.strokeStyle = 'blue';
ctx.beginPath();
ctx.moveTo(10, 10)
ctx.lineTo(100, 10)
ctx.lineTo(100, 100)
ctx.lineTo(10, 100)
ctx.lineTo(10, 10)
ctx.closePath()
ctx.stroke()
ctx.fill();

Превратить в цепочку:
ctx
.fillStyle('#eee')
.strokeStyle('blue')
.beginPath()
.moveTo(10, 10)
.lineTo(100, 10)
.lineTo(100, 100)
.lineTo(10, 100)
.lineTo(10, 10)
.closePath()
.stroke()
.fill();

Sausage.js — 1268 байт (скоро будет меньше килобайта), решающие ваши проблемы.
«Luke, use __noSuchMethod__» — и все дела, скажете вы. А как же поддержка доисторических браузеров?
Все кто не равнодушен к Canvas, цепочками вызовов и к Lisp прошу под кат


Почему Sausage и при чем тут Lisp?


Этот код (кроссбраузерный, делает тоже самое, что и первый блок) можно использовать, применив Sausage.js.
// Собираем словарь для удобства
(function(getContext, querySelectorAll, fillStyle, strokeStyle, beginPath, moveTo, lineTo, closePath, stroke, fill){

var canvasContext = $$(document)(querySelectorAll, 'canvas')(0)(getContext, '2d')();
$$(canvasContext, {fixedContext: true})
(fillStyle, '#eee')
(strokeStyle, 'blue')
(beginPath)
(moveTo, 10, 10)
(lineTo, 100, 10)
(lineTo, 100, 100)
(lineTo, 10, 100)
(lineTo, 10, 10)
(closePath)
(stroke)
(fill)
();

}('getContext', 'querySelectorAll', 'fillStyle', 'strokeStyle', 'beginPath', 'moveTo', 'lineTo', 'closePath', 'stroke', 'fill'));

Такие цепочки похожи на сосиски — поэтому так и назвал Сосиска.js, участие лиспа тут, конечно никакого, просто любители оценят большое количество круглых скобок :)

Почему бы не эмулировать __noSuchMethod__?


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

Изначально я вообще не планировал добавлять __noSuchMethod__, но потом решил, что так будет правильно. И название библиотеки Sausage сейчас частично утратило свой смысл.

Браузеры, которые поддерживают __noSuchMethod__ могут работать с Sausage в любой удобной форме:
$$(canvasContext, {fixedContext: true})
(fillStyle, '#eee')
(strokeStyle, 'blue')
.beginPath()
(moveTo, 10, 10)
(lineTo, 100, 10)
.lineTo(100, 100)
(lineTo, 10, 100)
(lineTo, 10, 10)
(closePath)
.stroke()
.fill()
();


Примеры использования Sausage.js


Пример 1. Переключание контекста

context = {'foo': {'bar': '100500'}, 'bar': '888', 'zoo': /./};
// Создаем Сосиску с контекстом {'foo': {'bar': '100500'}, 'bar': '888', 'zoo': /./}
result = $$(context)
('foo')     // Переключаем контекст сосиски на {'bar': '100500'}
('bar', -1) // Меняем значение
('zoo')     // Переключаем контекст на zoo
();         // Получаем значение контекста - undefined т.к. у объекта foo нет свойства/метода zoo


Пример 2. Фиксированный контекст

context = {'foo': {'bar': '100500'}, 'bar': '888', 'zoo': /./};
// Создаем Сосиску с контекстом {'foo': {'bar': '100500'}, 'bar': '888', 'zoo': /./}
result = $$(context, {fixedContext: true})
('foo')     // Переключаем контекст сосиски на {'bar': '100500'}
('bar', -1) // Меняем значение
('zoo')     // Переключаем контекст на zoo
();          // Получаем значение контекста - /./


Пример 3. Вызов функций — изменение значения контекста

context = {'foo': 1};
// Создаем Сосиску с контекстом {'foo': 1}
result = $$(context)
('foo', 1000) // Меняем значение переменной контекста
(function (context) { // Передаем функцию для обработки контекста
    return '' + context.foo / 2; // Возвращаем текущий контекст - строка '500'
})
('length') // Переключаем контекст на длину строки
(function (context) {
    return typeof context; // Возвращаем текущий контекст - строка 'number'
})
(); // Получаем значение контекста number


Пример 4. Обертка DOM

result = $$(document)
('getElementById', 'div1')
('style')
    ('width', '100px') // Меняем свойство
    ({  // Передаем объект для редактирования свойств/ вызовов методов пачкой
        height: '100px',
        color: 'red',
        border: 'solid 1px blue'
    })
(); // CSSStyleDeclaration Object


Пример 5. Обертка jQuery

result = $$(jQuery)
(['#div2']) // Если первый аргумент массив и контекст - функция, то контекст вызывается с параметрами в массиве
('css', {width: '100px', height:'100px', color: 'red', border: 'solid 1px blue'})
('animate', {width: '200px', height:'200px'})
(); // jQuery


Профилирование


Для запуска профилирования, необходимо подключить версию со включенным профейлером и запустить профилирование.
$$.profile();
// Ваш сосисочный код
console && console.dir($$.profileEnd());

В результате получим
[anonymous function] Object { calls=2, time=0}
[context call]	    Object { calls=1, time=0}
[switching context]  Object { calls=7, time=0}
animate              Object { calls=1, time=5}
bar                  Object { calls=2, time=0}
width                Object { calls=1, time=0}


Минусы


— Для удобства необходимо собирать словарь методов/свойств (если использовать сосисичную нотацию)
— Прощай autocomplete (если использовать сосисичную нотацию)
— Вызовы немного медленее
— При точечной нотации невозможно вызвать меотды/свойства, которые есть у функций (length, call, apply, ...) нельзя — $$([1,2,3]).length()();, можно — $$([1,2,3])('length')();

Плюсы


— За счет словаря, отсутствия точки и применения цепочек — значительное сокращение объема кода после сжатия
— Возможность кроссбраузерно профилировать вызовы и считать количество вызовов
— Обработка «Пачкой»

Ссылки


Живой пример jsfiddle.net/azproduction/LUXwY
Не упакованная версия с комментами (9168 байт) sausage-js.googlecode.com/svn/trunk/Sausage.js
Упакованная версия (1268 байт) sausage-js.googlecode.com/svn/trunk/Sausage.min.js
Версия с профайлером sausage-js.googlecode.com/svn/trunk/Sausage-profile.js

Критика, пожелания и предложения приветствуются.

UPD Добавлено описание профилирования
Tags:
Hubs:
+5
Comments 6
Comments Comments 6

Articles