Заметки с тегом «hint»

Размер объекта в памяти

Если вам для каких-то целей потребовалось узнать сколько памяти занимает какой-либо объект в браузере, то инструменты разработки помогут вам это сделать. В Chrome DevTools в разделе Memory можно сделать снимок памяти и посмотреть какие там есть объекты на данный момент времени. Однако, без подготовки найти нужные данные будет совсем не просто.

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

Начнем с того, что сделаем первый снимок памяти браузера.

Делаем начальный снимок памяти

Теперь переключимся в раздел Console и добавим какой-то тестовый объект.

Создаем объект в консоли

Затем делаем ещё один снимок памяти. Укажем в селекторе, что нужно показать только объекты, созданные между первым и вторым снимком.

Retained size объекта

В списке станет значительно меньше данных. Нас интересует именно Object. И первым же выбранным элементом оказывается наш тестовый объект.

В колонке Retained Size будет указано сколько памяти он занимает. В моём случае это 2488 байт.

Создадим ещё аналогичный объект, но с другими данными.

Создаем другой объект в консоли

Сделаем ещё один снимок экрана и обнаружим, что размер занимаемой памяти теперь значительно уменьшился. Второй объект у меня занимает 736 байт.

Новый объект занимает меньше памяти

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

Грубо оценить эти расходы можно следующим образом:

  • 2 байта на символ строки
  • 8 байт на число
  • 4 байта на булевское значение

Значит мои тестовые объект со случайными значениями полей будут занимать примерно 420-500 байт. Плюс, нужно учесть накладные расходы на хранение структур самих объектов.

Чтобы проверить эту оценку, загрузим 10 тысяч объектов, подобных тем, что я использовал в предыдущих примерах.

Загружаем 10000 объектов

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

Теперь в снимке памяти нас интересует массив.

Массив с тестовыми данными

Итак, загруженные данные (10 тысяч объектов) занимают 4959384 байта, что в пересчете на один объект будет 496 байт. Это значение хорошо вписывается в оценку.

Оставте свой комментарий

Код состояния HTTP для неавторизованного пользователя

Среди официального списка кодов состояний HTTP есть такой код:

401 Unauthorized

The request requires user authentication.

И разработчики ошибочно начинают его применять в ответах на REST-запросы асинхронные запросы, чтобы сообщить браузеру о том, что текущий пользователь их приложения не авторизован. Это в корне неверно.

В описании кода 401 ясно указано, что вместе с таким ответом сервер должен передать заголовок WWW-Authenticate с перечнем условий. А браузер может повторить запрос, включив в него заголовок Authorization с требуемыми для аутентификации данными.

Чаще всего в реальной жизни этот код можно встретить, если доступ к ресурсу защищён паролем. Например, в Apache это можно сделать добавив в конфигурацию следующие строки:

AuthName "Secure Area"
AuthType Basic
AuthUserFile "/usr/local/apache/passwd/passwords"
Require valid-user

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

Очевидно, что такая проверка уровня доступа пользователя к запрашиваемому ресурсу по протоколу HTTP никак не связана с разграничением прав пользователей внутри сервера приложения.

А как лучше?

По моему мнению, разумнее отвечать неавторизованному пользователю кодом 403 Forbiden

403 Forbidden

The server understood the request, but is refusing to fulfill it.

А в теле ответа передать JSON с описанием проблемы.

Комментарии к заметке: 4

Ссылка на глобальный объект в JavaScript

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

function myCoolFunction() {
  var global = function () { return this; }();
}

Переменная global внутри myCoolFunction() будет соответствовать window, если код выполняется в браузере, и global для окружения Node.js.

Однако, когда функция выполняется в строгом режиме, такой трюк не пройдёт. В «strict mode» значение this будет равно undefined.

function myCoolFunction() {
  'use strict';
  var global = Function('return this')();
}

Этот приём работает корректно из-за того, что функция, созданная с помощью конструктора Function, не наследует «строгость».

Оставте свой комментарий

Безопасное получение свойств вложенных объектов

Доступ к свойствам вложенных объектов через «.» или «[]» опасен тем, что если в цепочке не будет указанного объекта, то будет выброшено исключение.

var obj = {a: {b: {c: 42} } };
obj.a.x.y;

TypeError: Cannot read property ‘y’ of undefined

От таких ситуаций можно обезопаситься, если воспользоваться простой функцией.

function getProperty(obj, prop) {
  return prop.split('.')
    .reduce(function (m, i) {
      return m && typeof m == 'object' ? m[i] : null;
    }, obj);
}

var obj = {a: {b: {c: 42} } };
getProperty(obj, 'a.x.y');

null

Комментарии к заметке: 9

Шпаргалка по созданию RESTful API

RESTful API может создаваться не только для сторонних сервисов. Он может использоваться одностраничными приложениями для работы с бэк-эндом. Вот несколько основных моментов, которые нужно знать при проектировании интерфейса.

URLs и действия

Ключевым принципом REST является деление вашего API на логические ресурсы. Управление этими ресурсами происходит с помощью HTTP-запросов с соответствующим методом — GET, POST, PUT, PATCH, DELETE.

Ресурс должен описываться существительным во множественном числе. Действия над ресурсами, обычно, определяются стратегией CRUD и соответствуют HTTP-методам следующим образом:

  • GET /api/users — получить список пользователей;
  • GET /api/users/123 — получить указанного пользователя;
  • POST /api/users — создать нового пользователя;
  • PUT /api/users/123 — обновить все данные указанного пользователя;
  • PATCH /api/users/123 — частично обновить данные пользователя;
  • DELETE /api/users/123 — удалить пользователя.

Если ресурс существует только в контексте другого ресурса, то URL может быть составным:

  • GET /api/posts/9/comments — получить список комментариев к записи №9;
  • GET /api/posts/9/comments/3 — получить комментарий №3 к записи №9.

Когда действие над объектом не соответствует CRUD операции, то его можно рассматривать как составной ресурс:

  • POST /api/posts/9/like — отметить запись №9 как понравившуюся;
  • DELETE /api/posts/9/like — снять отметку «понравилось» с записи №9.

Действия по созданию и обновлению ресурсов должны возвращать ресурс

Методы POST, PUT или PATCH могут изменять поля ресурса, которые не были включены в запрос (например, ID, дата создания или дата обновления). Чтобы не вынуждать пользователя API выполнять ещё один запрос на получение обновлённых данных, такие методы должны вернуть их в ответе.

Фильтры, сортировка и поиск

Любые параметры в HTTP-запросе могут быть использованы для уточнения запроса или сортировки данных.

  • GET /api/users?state=active — список активных пользователей;
  • GET /api/tasks?state=open&sort=priority,-created_at — список невыполненных задач, отсортированных по приоритету и дате создания (сперва новые задачи).

Постраничная навигация

Когда нужно в ответ на запрос списка объектов добавить информацию о постраничной навигации, стоит воспользоваться HTTP-заголовком Link, а не добавлять обёртки данным.

Пример заголовка:

Link: <http://domain.tld/api/users?page=5&per_page=100>; rel="next",
    <http://domain.tld/api/users?page=3&per_page=100>; rel="prev",
    <http://domain.tld/api/users?page=1&per_page=100>; rel="first",
    <http://domain.tld/api/users?page=10&per_page=100>; rel="last"

Возможные значения rel:

  • next — следующая страница результатов;
  • prev — предыдущая страница результатов;
  • first — первая страница результатов;
  • last — последняя страница результатов.

Важно следовать этим значениям, а не конструировать собственные URL-ы потому, что иногда постраничная навигация может основываться на сложных правилах, а не простом переборе страниц.

Переопределение HTTP-метода

Для совместимости с некоторыми серверами или клиентами, которые не поддерживают другие HTTP-методы кроме GET и POST, может быть полезным их эмуляция. Значение метода передаётся в заголовке X-HTTP-Method-Override, а сам он выполняется как POST-метод. GET-запросы не должны менять состояние сервера!

Коды HTTP-статуса

  • 200 OK — ответ на успешный запрос GET, PUT, PATCH или DELETE.
  • 201 Created — ответ на POST запрос, в результате которого произошло создание нового объекта. Ответ так же должен сопровождаться заголовком Location, указывающий на URL ресурса.
  • 204 No Content — ответ на успешно выполненный запрос, который ничего не возвращает (например, DELETE).
  • 404 Not Found — запрашиваемый объект не найден.
  • 500 Internal Server Error — ошибка на сервере.

В случае ошибок, в ответе может содержаться отладочная информация для разработчиков, если это возможно.

Метаданные

Любые данные, которые лишь опосредованно относятся к результату запроса, но могут быть полезны клиенту, стоит отдавать в виде HTTP-заголовков. Создание обёрток над данными ломает совместимость с принципами REST.

Оставте свой комментарий