Создание удобного обработчика AJAX-запросов

в 6:45, , рубрики: Без рубрики

Многие сталкивались с проблемой огромного количества post и get запросов по ходу разработки сайта. В частности, в разработке на jQuery, где не один запросик-стучалка, а куча запросов в тех-же самых магазинах: корзина, избранное, фильтр. Да что я распыляюсь. Все и так прекрасно понимают прелести разработки больших проектов.

Вроде бы оно и быстро реализовано на JQ… но как-то не очень. Все равно тратятся драгоценные символы и время на создание удобного кода.

Столкнувшись с этой проблемой в 105 раз, решил — хватит. Пора что-то менять. И поменял.

Суть приёма такая:
Для обработки запросов используем один файл с классом-обработчиком. Он принимает запросы и роутит их на соответствующий метод объекта обработчика. Чтобы не заморачиваться долго, было решено и коллбэк выводить обязательно ( см. функцию retJSON) из свойства объекта CLBK.
Соответственно, отправление/получение происходит также с помощью одного метода. В параметры JS-метода включается отдельно название метода и отдельно — все остальное.

Данный способ позволил мне:
1. Избавиться от тучи файлов-обработчиков.
2. Хоть как-то привести код в порядок, вместо обыкновенного JQ-бедлама.
3. Создать определённую структуру кода и даже возможность расширения приложения.
4. Повысить читаемость кода. Будучи программистом культурным («Господи Иисусе!», — возопят знатоки предмета. — «ты же совсем не понимаешь принципов программирования, какая тут культура.» Может быть где-то недочитал матчасть, но плевать я хотел на ихнее мнение, если честно. Мне так комфортно ) в последнее время стал задумываться и о людях, которые после меня будут разбираться в моих строчках. Посему потратил пару дополнительных часов.

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

Ниже скрипты и пример использования обработчика.

var JQ = $;
var Core = {

        rmvFrmBskt: function(id){
	
		this.request(arguments.callee,{ID:id},function(data){
			
			if(data.status === "OK")
				Core.getBskt();
		})
	},

	request:function(method,params,callback_fnc){
		
		if(	
			(
				typeof method !== 'string'&&
				typeof method !== "function"
			)||
			typeof params !== "object"||
			params === null
		)
		throw "Core.request::Arguments isn't valid";
		
		if(typeof method !== 'string')
			method = Hlp.getMthName(this,method);
		
		if(method==='') throw "Core.request:: method is hollow";
		JQ.post("/callback.php",{"method":method,"params":params},function(data,callback){
		
			try{var JSONobj = JSON.parse(data)}
			catch(e){
				throw(e);
			}
			if(JSONobj.error){
				throw "Core.request:: " + JSONobj.error;
			}
			
			if(JSONobj.notify_text){
				
				alert(JSONobj.notify_text);
				throw "Core.request:: " + JSONobj.notify_text;
			}
			
			if(JSONobj.echo){
				if(Util.bid("debugdiv"))
				Util.rmv(Util.bid("debugdiv"));
				var dbg = Util.crt("div","debugdiv");
				body.appendChild(dbg);
				dbg.innerHTML = JSONobj.echo;
			}
			callback_fnc(JSONobj);
		});
	}


var Hlp = {

    getMthName:function(obj,mth) {
		var mthName = '';
        for (var i in obj) {
			if(obj[i]===mth){
				mthName =  i;
				break;
			}
		};
		return mthName;
    }
}


var Util = {
	bid: function(id){
		if(!!id){
			return document.getElementById(id);
		}
	},
	rmv: function(Node){
		Node.parentNode.removeChild(Node, Node.parentNode);
	},
	rmvAllCh: function(Node){
		var cnt = Node.children.length;
		
		for(var k = 0; k < cnt; k++){
		
			Util.rmv(Node.children[0]);
		}
	},
	bc: function(className){
	
		var Node = document.getElementsByClassName(className);
		
		if(Node.length==1){
			
			return Node[0];
		}else{
			return Node;
		}
	},
	crt: function(Node, className, attr){
		var tmp = document.createElement(Node); 
		if((typeof className === 'string')&&(className!='')){
		
			tmp.className = className;
		}
		
		if(typeof attr === 'object'&&attr != null){
			for(var i in attr){
			
				tmp[i] = attr[i];
			}
		}
		return tmp;
	}

}

Немного PHP

class CallBack{
	
	public static $CLBK = Array();
	
	static function router(){
		
		if(	!CModule::IncludeModule("catalog")||
			!CModule::IncludeModule("sale")||
			!CModule::IncludeModule("iblock")){
			
				CallBack::retJson(Array("error"=>"PHP CModule isn't included"));
				die();
			}
	
		if(isset($_REQUEST)&&!empty($_REQUEST)&&method_exists("CallBack", $_REQUEST['method']."Clbk")){
		
			$methodName = $_REQUEST['method']."Clbk";
			CallBack::$methodName($_REQUEST['params']);
		}else{
			CallBack::retJson(Array("error"=>"PHP Callback.router::invalid arguments"));
		}
	}
	
	static function retJson(){
	
		if(!is_array(self::$CLBK)) die();
		
		echo json_encode(self::$CLBK);
	}

public function rmvFrmBsktClbk($PARAMS){
	
		CSaleBasket::Delete((int)$PARAMS['ID']);
		self::$CLBK['status'] = "OK";
	}
}


CallBack::router();
CallBack::retJson();

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

Автор: Ngorco

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js