Carduelis
@Carduelis
Web-developer, front-end, js, less

Как лучше сделать проверку пользовательских прав на js?

DISCLAIMER. У нас one-page js app, к сожалению, написанный без angular'a и backbone. Проект начинался не нами, а писать с нуля времени не было.

Суть вопроса:
В js вызывается функция с ajax-запросом пользовательских прав. Там приходит массив с 0 и 1, и за что они отвечают. В зависимости от этого надо менять UI.

Так как функция-инициализатор основного интерфейса (шаблонизатор lodash используется) стартует сразу после document.ready, как лучше всего организовать условия проверки? Ведь, что раньше произойдет document.ready или ajax-запрос данных о доступе, мы знать не можем.

Сейчас есть такое решение:

var access = {}
function getAccess() {
   $.get('url', function(data) {
      access = data;
      start();
   }
}
getAccess(); // вызываем проверку до document.ready();
function start() {
   $(function(){
      if (access.read) {
            // генерится шаблон
      } else {
            // генерится шаблон "В доступе отказано"
      }
   }
}


Как сделать этот код красивым и удачным? Почему такое решение плохое и плохое ли?

UPD.
Подумав немного, решил воспользоваться следующей структурой
function permissionsRecieved() {
   if (access.read || access.readAll) {
      // генерим шаблончик
   }    
}
access = {
    getPermissions : function() {
        // get-запрос, по .done - вызываем access.ready
        $.get('бла-бла', function(data) { 
              Object.assign(access, data) // подгрузили всякие read/write и добавили к access
              access.ready()
        }, 'json')
    },
	ready : function() {
                // вот здесь пришедшая в голову идея отказаться от $.ready и всего такого
		document.onreadystatechange = function () {
			if (document.readyState == 'complete') {
				return permissionsRecieved();
			}
		}
	}
}


UPD 3
Протестив, понял, что по "complete" нельзя делать так, ввиду возможного наличия больших css и картиночек на странице. А "interactive" не всегда вызывается по document.onreadychange внутри ready, так как ajax-запрос был позже interactive.
ready : function() {
		console.info('Access ready. Current app ('+access.moduleName+') may be initiated');
		if ((document.readyState == 'interactive') || (document.readyState == 'complete')) {
			startApp();  // бывш. permissionRecieved() - начинаем генерить шаблончики, сперва проверив права
		} 
		document.onreadystatechange = function () {
			console.info(document.readyState); // смотрим, когда выходит 'complete', а может быть, и отловим 'interactive', когда ajax выполнится ДО загрузки и обработки дом-дерева
		}
	}
  • Вопрос задан
  • 463 просмотра
Решения вопроса 1
$(document).ready(func) внутри себя использует $.Deferred, то есть, даже если DOM уже загрузился, при вызове этой конструкции или её сокращенного варианта переданная функция всё равно выполниться. Исходя из этого, код в вашем первом варианте работает надёжно и без задержек, нужно лишь сделать его лаконичней:

var permissionsAndDOM = $.Deferred();

$.get("url", function(access) {
	$(function() {
		permissionsAndDOM.resolve(access);
	});
});

permissionsAndDOM.done(function(access) {
	if (access.read) {

	} else {

	}
});

Если не понимаете, что здесь происходит - читайте про Promise (ES6), $.Deferred (jQuery-аналог Promise) и не помешает знать паттерн Pub-Sub (в JavaScript'е его обычно реализуют через функции on, off, trigger). Это всё основные инструменты для комфортной работы с ассинхронностью.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
sim3x
@sim3x
Концептуально - делаешь обертку над стандартным $.ajax, где внутри проверяешь права.
Запрос прав кешируешь на 5-10 минут
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы