Later Ctrl + ↑

Javascript сниппеты с google closure

Интересная возможность closure-compiler (это такой сервис для обфускации и оптимизации кода). Возможность складывается из двух факторов:

  • компилятор в advanced режиме пережимает код до неузнаваемости, попутно совершая оптимизации. Оптимизаций вагон: значения, которые можно вычислить, вычисляются, инлайновые функции “растворяются” в коде. Функции, которые не вызываются, выбрасываются.
  • компилятор работает с библиотекой гугла для javascript, позволяя совершать импорты модулей из библиотеки в тело скрипта.

Комбинируя эти знания, включаем библиотеку, и запрашиваем версию флеша, например:

// ==ClosureCompiler==
// @output_file_name default.js
// @compilation_level ADVANCED_OPTIMIZATIONS
// @use_closure_library true
// ==/ClosureCompiler==

goog.require('goog.userAgent.flash');
window.a = goog.userAgent.flash.VERSION

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

Ограничений не существует

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

«Нельзя курить» — это ограничение.
«При курении, вероятность рака увеличивается» — это условие. Статус и возможность чиркнуть спичкой я ценю больше, чем шанс заболеть раком.

«По газонам нельзя ходить» — ограничение.
«Если будешь ходить по газонам, милиция попробует тебя оштрафовать» — условие. Спасаясь от шпаны, я готов бежать через газон.

«Нельзя использовать eval» – это ограничение.
«Если использовать eval, код отработает медленнее и может нарушиться область видимости» — условие. В этом проекте я готов использовать eval, потому что он решает больше задач, чем создает проблем.

Примеры принятия ограничений на веру, без оценки:

  • Тест в первых людях в черном (ограничение — далеко стоящий стол).
  • свеча Карла Дункена (ограничение — кнопки, лежащие в коробке).
  • Как из 6 спичек сложить 4 треугольника (ограничение — работа в одной плоскости).
  • Тест. 2 группы, одинаковый список задач на выполнение. Одной сказали, что существуют люди, генетически предрасположенные к решению этих задач. Второй ничего не сказали. Испытуемые из первой справились в среднем хуже. (ограничение — не предрасположенность к решению задач).

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

Менее критичное мышление.
Если ограничение принимать на веру, при этом не давая ему оценки, ограничение превращается в непреодолимое препятствие. При этом вырабатывается привычка не давать количественную оценку условиям.
Следовательно — отсутствие иерархии ограничений. Следовательно — неумение действовать в ситуации, сложность которой колеблется относительно нормы.

Будьте честные с собой, живите без ограничений.

Рендер динамического markdown в jade

Jade среди прочих, имеет классную фичу — фильтры. Вот только они не завелись у меня с динамическим markdown. Как это часто бывает с javascript-ом, очевидное решение не срабатывает.

template.jade

markdown: #{md}

router.coffee

app.get "/" (request, response, next) ->
    response.render "template", 
         indexMarkdown : indexMarkdown

В браузер приходит сырой markdown без намека на конвертацию. Решением оказалось передача функции , которая умеет парсить markdown, параметром в шаблон, и запуск ее из самого шаблона:

template.jade

div= mdToHTML(indexMarkdown)

router.coffee


md = require("marked").parse

#...
app.get "/" (request, response, next) ->
    response.render "template", 
        indexMarkdown : indexMarkdown
        mdToHTML : md

Максимальная частота срабатывания события mousemove

В голову пришла мысль, что выстреливать событие движения мыши чаще 60 раз в секунду бесмысленно. После ручных тестов браузеры (O12, FF20.02a, S6.02, C24) показали полную солидарность в моих взглядах. Каждый из них запускал обработчик движения мыши не более 60 раз в секунду. Код для проверки в домашних условиях:

var start;
var totalCalls;


start = 0
totalCalls = 0

function onmove () {
	var now = Date.now()

	// начнем считать время с момента
	// первого срабатывания события mousemove
	if (!start) {
		start = now
	}

	if (now - start < 1000) {
		totalCalls += 1
	} else {
		console.log(totalCalls)
	}
}

window.onmousemove = onmove

После запуска кода веди мышку с одной скоростью по телу страницы.

Как запустить nodemon под forever

Примеры из документации устарели, да и в явном виде решения не нашел. В двух словах:

  • forever инструмент для запуска скриптов (не только nodejs) в фоновым процессом.
  • nodemon перезапускает скрипт после изменений файлов (в моем случае coffee).
forever start -c nodemon app.coffee

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

Базопасный placeholder-болванка javascript ответа

На сервере динамически генерируется javascript ответ (допустим script.js). При этом какая-то часть файла — статическая и одинаковая для всех клиентов, а какая-то должна быть заменена для каждого клиента отдельно. При этом заменой занимается некий серверный язык. Задача: предоставить файл-шаблон, в определенное место в котором будут подставляться данные. Первое, что приходит на ум выглядит как-то так:

(function () {
	var data = #DATA_PLACEHOLDER#;
	var errors = #ERRORS_PLACEHOLDER#;
	var all = {};
		
	all.data = data;
	all.errors = errors;
	window.provide = processData(all);
}());

Файл получается невалидным, что влечет ряд последствий:

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

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

(function () {
	var data = (function () {return /*!DATA_PLACEHOLDER*/})() || {};
	var errors = (function () {return /*!ERRORS_PLACEHOLDER*/})() || [];
	var all = {};
	
	all.data = data;
	all.errors = errors;
	window.provide = processData(all);
}());

Уже намного лучше. Файл валиден, теперь его можно не исключать из процесса проверки всего проекта. А так-же в случае с проблемами на бекэнде, клиентская часть продолжает инициализироваться. Тут она сможет сама решить, как поступать в случае падения серверов.

Однако не все так безрадостно.

var data = (function() {return
	{
		importantValue: true
	}
})() || {};
console.log(data.importantValue); // undefined

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

И вот оно, финальное решение: передадим данные аргументом, и вернем их-же.

(function () {
	var data = (function (data) {return data})(/*!DATA_PLACEHOLDER*/) || {};
	var errors = (function (errors) {return errors})(/*!ERRORS_PLACEHOLDER*/) || [];
	var all = {};
		
	all.data = data;
	all.errors = errors;
	window.provide = processData(all);
}());

На выходе — пуленепробиваемая, валидная конструкция для последующего наполнения данными.

Максимальная глубина рекурсивного вызова

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

var max_depth;

max_depth = 0;
function recursive () {
	max_depth += 1;
	recursive();
}
try {
	recursive()
} finally {
	alert('Max recursion depth is ' + max_depth);
}

Визуализация
Browser call stack limits

Сырые данные

Safari 6.02 43680
Chrome 23 (mac) 24544
Chrome 23 (win) 25021
Opera 12.10 16384
Firefox Aurora 19.0a2 31712
Internet explorer 41153
nodejs 25113

Все браузеры, кроме firefox-а давали ответ практически моментально. А лисица висела минуты 3-4, прежде чем назвать свою цифру.

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

Earlier Ctrl + ↓