Возможно, данный эпиграф имеет ко мне большее отношение, чем я думаю, но хочется надеяться на лучшее…
Мой первый пост получился, мягко говоря, не очень, но у любого человека должна быть возможность все исправить и сейчас я попробую этим воспользоваться.
Расскажу небольшую историю, которая случилась со мной на работе. Дело было давно, как-то приасанили меня к новому web-проекту, проектированием которого я не имел ни малейшего отношения. Тимлид первым делом залил в svn php и js framework’и.
В качестве JS был выбран Mootools 1.2.2 или 1.2.4, а в дополнение к нему Jx UI Library в виде JxLib. Все шло хорошо, проект подходил к своему завершению, версии браузеров росли и тд. И вот, в один прекрасный момент, придя на работу я увидел баг, в кором говорилось а том что в IE9 (а он только-только вышел) админка не работает вообще. Первым делам начал искать проблему, как оказалось Mootools 1.2.x — не поддерживает IE9, а вот в версиях over 1.3.x — все работает и летает. Ну, долго не думая, качаем последнюю версию сего чуда и ставим. Радоватся пришлось не долго — начали вылазить баги в JxLib. Оказывается, что проект ‘заглох’, и последняя доступная версия совместима только с Mootools 1.2.x. Много времени прошло с того момента, но тот говнокод, с помощью которого пришлось залатать этот баг, надломал мою веру в Mootools и ему подобные вещи. Теперь, я думаю, стало ясно, откуда такое отношение к JS либам.
А теперь хочется ответить (пояснить почему так, а не иначе) на некоторые комментарии.
1)
Сonsole.log — вот этого я не ожидал, я предлогал многое но только не это. Я в курсе того что он (console.log) поддерживает форматирование и передачу нескольких параметров, но я не могу вспомнить, когда последний раз я этим пользовался. Мне вполне хватает одной переменной, а усложнять _d() ради того чтобы использовать всю мощь сonsole.log раз в месяц, — нецелесообразно (проще написать заветные 11 символов `сonsole.log`).
2)
Функция addEvent продолжит выполняться после обработки ошибки с помощью функции _d.
— я в курсе этого, это сделано специально, ибо проверку на существование DOM объекта, а предпочитаю делать в основном скрипте, но вы меня меня убедили — добавлю return false.
3)
Загрязнение глобального пространства переменных — очень плохой тон.
— тут вы правы, но кроме readyList = []; я ничего не могу найти глобального 🙂
Ну что ж, я думаю пора заканчивать эти холивары и начать рассмотрение новой партии JS кода.
// Учитывая какие гуру сидят на хабре - первые 3 функции (тем более что их названия сами за себя говорят) я оставлю без комментариев /** * Function insert DOM element before some element * * @version 2012-11-06 * @param Object new_element * @param Object targetElement * @return void */ function insertBefore(new_element, targetElement) { targetElement.parentNode.insertBefore(new_element, targetElement); } /** * Function insert DOM element after some element * * @version 2012-11-06 * @param Object new_element * @param Object targetElement * @return void */ function insertAfter(new_element, targetElement) { var parent = targetElement.parentNode; //if the parents lastchild is the targetElement... if(parent.lastchild == targetElement) parent.appendChild(new_element); else parent.insertBefore(new_element, targetElement.nextSibling); } /** * Function make clone of income object * * @version 2012-11-07 * @param Object obj * @return Object */ function clone(obj) { if(obj == null || typeof(obj) != 'object') return obj; var temp = {}; for(var key in obj) temp[key] = clone(obj[key]); return temp; } // Функция вернет следующий DOM объект в узле, если такой существует /** * Function return next element in dom object * * @version 2013-01-08 * @param Object obj * @return Object */ function getNext(obj) { obj = obj.nextSibling; if(!obj) return false; while(obj.nodeType != 1){ obj = obj.nextSibling; if(!obj) return false; } return obj; } // Функция вернет предыдущий DOM объект в узле, если такой существует /** * Function return previous element in dom object * * @version 2013-02-13 * @param Object obj * @return Object */ function getPrevious(obj) { obj = obj.previousSibling; if(!obj) return false; while(obj.nodeType != 1){ obj = obj.previousSibling; if(!obj) return false; } return obj; } // Следующие 2 функции - это установка и чтение Cookies. C ними, я думаю, проблем не будет /** * Function new Cookies * * @version 2013-03-26 * @param string name * @param string value * @param string expires * @param string path * @return void */ function setCookies(name, value, expires, path) { if(!name || !value) return 0; if(!expires){ expires = new Date(); expires.setTime(expires.getTime() + (1000 * 86400 * 365)); //save 1 year } if(!path) path = '/'; // set Cookies document.cookie = name+'='+escape(value)+'; expires='+expires.toGMTString()+'; path='+path; } /** * Function return Cookies value by name * * @version 2013-03-26 * @param string name * @return void */ function getCookies(name) { var results = document.cookie.match ( '(^|;) ?' + name + '=([^;]*)(;|$)' ); if ( results ) return ( unescape ( results[2] ) ); else return null; } // А вот здесь придется задержатся // Вначале создаем функцию Ajax(params), а потом прикручиваем к ней prototype /** * Ajax object * * Send request by post/get to some url * * @version 2013-02-13 * @param Object params * @return Object */ window.Ajax = function(params) { // параметры по умолчанию this.options = { // default url url: '', // default method method: 'get', // Is synchronous request? async: true, // in seconds timeout: 10000, // callback function, in default - empty function onComplete: function(){} }; // set config params this.setConfig(params); // создаем и подготавливаем кроссбраузерный XMLHttpRequest для дальнейшей работы // initialize this.init(params); }; /** * Pablic methods */ window.Ajax.prototype = { /** * some internal params */ xml_http_request: null, timeout: null, // json|xml|text response:'json', // устанавливаем параметры ajax запроса, если таковы были переданы /** * configure functionality */ setConfig: function(opt) { // set url if(opt.url != undefined) this.options.url = opt.url; // set method if(opt.method != undefined) this.options.method = opt.method; // set asynchronus param if(opt.async != undefined) this.options.async = opt.async; // set timeout if(opt.timeout != undefined) this.options.timeout = opt.timeout; // set callback functions if((opt.onComplete != undefined) && (typeof(opt.onComplete) == 'function')) this.options.onComplete = opt.onComplete; }, /** * Initialize XMLHTTPRequest */ init: function() { // кроссбраузерное создание XMLHttpRequest // Cross-browser compatibility for browsers if (typeof XMLHttpRequest != 'undefined') { this.xml_http_request = new XMLHttpRequest(); } else{ try { this.xml_http_request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { this.xml_http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) { alert('Your brouser don\'t support Ajax technology. Please download real browser :)'); } } } var self_ = this; // устанавливаем метод (post/get), url, синхронный/несинхронный запрос // open XMLHttpRequest this.xml_http_request.open(self_.options.method, self_.options.url, self_.options.async); /** Вешаем callback в случае успешного * * Список состояний readyState такой: * 0 - Unitialized * 1 - Loading * 2 - Loaded * 3 - Interactive * 4 - Complete * Состояния 0-2 вообще не используются. * * self_.xml_http_request.status - код ответа сервера (200, 404 и тд) */ // set callback function for XMLHttpRequest this.xml_http_request.onreadystatechange = function(){ if((self_.xml_http_request.readyState == 4) && (self_.xml_http_request.status > 0)){ // отмена принудительного разрыва Ajax запроса (ниже будут пояснения) // delete timeout clearTimeout(self_.timeout); // в завивимости от того, что вы ожидаете формируем ответ сервера // JSON.parse - встроеный парсер JSON (старые браузеры - bye-bye) if(self_.response == 'json') var response = JSON.parse(self_.xml_http_request.responseText); else{ if(self_.response == 'xml') var response = self_.xml_http_request.responseXML; else var response = self_.xml_http_request.responseText; } // вызываем обработчик результатов self_.options.onComplete(response); } } }, // Данный метод нужен в очень специфических задачах, когда необходимо играться с заголовками для сервера /** * Set some headers if need */ setRequestHeader: function(name, value) { this.xml_http_request.setRequestHeader(name, value); }, // Отсылаем Ajax на сервер /** * Send request */ send: function(params) { this.xml_http_request.send(params); var self_ = this; // про это я говорил ранее, если вас запрос повис или на серваке проблемы - обрываем его принудительно // по умолчанию - 10 секунд ждем, хотя можно и больше // set timeout need for abort request this.timeout = setTimeout( function(){ self_.xml_http_request.abort(); }, this.options.timeout); }, // Данная фишка для того, что бы вы могли в любое время прервать запрос, например при живом поиске (как у хабра или гугла :) ) /** * Abort request */ abort: function() { this.xml_http_request.abort(); } } Пример использования Ajax(): new Ajax({ url: '/index.php', timeout: 20000, method: 'post', onComplete: function(data){ alert(data);} }).send('qwerty=123');
PS. Как и обещал, исходники. Статья написана для того, что бы люди не забывали истинный JavaScript и переходила на светлую сторону силы (печеньки тут тоже имеются 🙂 ).
ссылка на оригинал статьи http://habrahabr.ru/post/176273/
Добавить комментарий