<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>JavaScript</title>
	<atom:link href="https://consultapp.ru/category/stati/javascript/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Веб-разработка, сопровождение информационных систем</description>
	<lastBuildDate>Mon, 01 Jul 2024 11:12:40 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
	<item>
		<title>Некоторые тонкости методов JSON stringify и parse в JavaScript</title>
		<link>https://consultapp.ru/interesting-moments-in-json-stringify-parse-in-javascript/</link>
		
		<dc:creator><![CDATA[Дмитрий]]></dc:creator>
		<pubDate>Wed, 26 Jun 2024 20:07:37 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Статьи]]></category>
		<guid isPermaLink="false">https://consultapp.ru/?p=1950</guid>

					<description><![CDATA[<p>Методы JSON.stringify() и JSON.parse() служат для преобразования объекта в json и восстановления json в объект JS соответственно. Однако, они работают не со всеми элементами объекта корректно, а некоторые в целом игнорируются, что следует учитывать при копировании. Здесь мы рассмотрим 2 момента, а именно невозможность перевода в JSON формат функций и символов, а так же ошибку/несоответствие&#8230;</p>
<p>Сообщение <a href="https://consultapp.ru/interesting-moments-in-json-stringify-parse-in-javascript/">Некоторые тонкости методов JSON stringify и parse в JavaScript</a> появились сначала на <a href="https://consultapp.ru">ConsultApp.ru</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Методы <code>JSON.stringify()</code> и <code>JSON.parse()</code> служат для преобразования объекта в json и восстановления json в объект JS соответственно. Однако, они работают не со всеми элементами объекта корректно, а некоторые в целом игнорируются, что следует учитывать при копировании. </p>



<span id="more-1950"></span>



<p>Здесь мы рассмотрим 2 момента, а именно невозможность перевода в JSON формат функций и символов, а так же ошибку/несоответствие при восстановлении данных на примере объекта типа <code>Date</code></p>



<h2 class="wp-block-heading">Введение</h2>



<p>Возьмем объект со свойствами разных типов данных и методом:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript line-numbers">const ticket = {
  isValid: true, // boolean
  price: 2000.0, // number
  cityFrom: "MSK", // string
  cityTo: "SPB", // string
  date: new Date(), // Date()
  *[Symbol.iterator]() {
    for (const item of Object.entries(this)) yield item;
  }, // function
};
console.dir(ticket);
// {
//     isValid: true,
//     price: 2000,
//     cityFrom: 'MSK',
//     cityTo: 'SPB',
//     date: 2024-06-27T10:05:33.522Z,
//     [Symbol(Symbol.iterator)]: [GeneratorFunction: [Symbol.iterator]]
// }</code></pre>



<p>Так же нам для наглядности понадобиться функция проверки типов свойств. Для нашего объекта она выдает ожидаемые значения <code>typeof</code>:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript line-numbers">function testTypes(obj) {
  for (const k in obj) console.log(k, typeof obj[k]);
}

testTypes(ticket);
// isValid boolean
// price number
// cityFrom string
// cityTo string
// date object</code></pre>



<h2 class="wp-block-heading">Стандартное преобразование</h2>



<p>Обычно объект преобразуют напрямую, следующий код показывает сопутствующие моменты:</p>



<ul class="wp-block-list">
<li>При упаковке мы потеряли метод Symbol(Symbol.iterator);</li>



<li>При восстановлении теряется тип данных даты, она становится строкой.</li>
</ul>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript line-numbers">{
  const json = JSON.stringify(ticket);
  console.log(json);
  // json = {"isValid":true,"price":2000,"cityFrom":"MSK","cityTo":"SPB","date":"2024-06-27T10:05:33.522Z"}
  // Здесь мы встречаемся с первым моментом. Видно, что не все упаковалось, функцию мы уже потеряли.

  const parsedObject = JSON.parse(json);
  console.dir(parsedObject);
  // {
  //     isValid: true,
  //     price: 2000,
  //     cityFrom: 'MSK',
  //     cityTo: 'SPB',
  //     date: '2024-06-27T10:05:33.522Z'
  // }

  testTypes(parsedObject);
  //   Если проверить типы, что мы увидим, 
  //   что дата теперь не объект, а строка.
  //   isValid boolean
  //   price number
  //   cityFrom string
  //   cityTo string
  //   date string
}</code></pre>



<h2 class="wp-block-heading">JSON.stringify()</h2>



<p>При упаковке, мы можем передать методу <code>JSON.stringify</code> второй параметр в виде массива ключей, которые надо экспортировать в json.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript line-numbers">const json = JSON.stringify(ticket, ["isValid", "price", "cityFrom", "date"]);
console.log("json:", json);
// json: {"isValid":true,"price":2000,"cityFrom":"MSK","date":"2024-06-27T11:18:08.648Z"}
// Проблема с датой осталась, но мы
// можем фильтровать нужные данные для передачи</code></pre>



<h2 class="wp-block-heading">JSON.parse()</h2>



<p>С методом <code>JSON.parse</code> все интересней, вторым аргументом можем передать функцию восстановления, с ее помощью мы сможем отслеживать интересующие нас поля и изменять их в процессе распаковки. </p>



<p>Пример функции восстановления для Date:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript line-numbers">function R(k, v) {
  if (
    typeof v === "string" &amp;&amp;
    /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(v)
  ) {
    return new Date(v);
  }
  return v;
}</code></pre>



<p>Код с функцией восстановления будет выглядеть так:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript line-numbers">{
  const json = JSON.stringify(ticket, ["isValid", "price", "cityFrom", "date"]);
  console.log("json:", json);
  // json: {"isValid":true,"price":2000,"cityFrom":"MSK","date":"2024-06-27T11:18:08.648Z"}
  // Проблема с датой осталась, но мы
  // можем фильтровать нужные данные для передачи

  // JSON.parse с функцией восстановления
  const recoveredObject = JSON.parse(json, function (k, v) {
    if (
      typeof v === "string" &amp;&amp;
      /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(v)
    ) {
      return new Date(v);
    }
    return v;
  });

  console.dir(recoveredObject);
  //   {
  //     isValid: true,
  //     price: 2000,
  //     cityFrom: 'MSK',
  //     date: 2024-06-27T11:24:24.112Z
  //   }

  testTypes(recoveredObject);
  // isValid boolean
  // price number
  // cityFrom string
  // date object
}
</code></pre>



<p>Мы видим, что дата стала объектом, тем самым, который мы вернули в функции восстановления. Естественно ее можно расширить, для восстановления например собственных типов объекто, если у них реализован метод toJSON() и они свободно упаковываются методом JSON.stringify.</p>



<h3 class="wp-block-heading">Итоговый код с комментариями</h3>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript line-numbers">function testTypes(obj) {
  for (const k in obj) console.log(k, typeof obj[k]);
}
const ticket = {
  isValid: true, // boolean
  price: 2000.0, // number
  cityFrom: "MSK", // string
  cityTo: "SPB", // string
  date: new Date(), // Date()
  *[Symbol.iterator]() {
    for (const item of Object.entries(this)) yield item;
  }, // function
};
console.dir(ticket);
// {
//     isValid: true,
//     price: 2000,
//     cityFrom: 'MSK',
//     cityTo: 'SPB',
//     date: 2024-06-27T10:05:33.522Z,
//     [Symbol(Symbol.iterator)]: [GeneratorFunction: [Symbol.iterator]]
// }
testTypes(ticket);
// isValid boolean
// price number
// cityFrom string
// cityTo string
// date object

{
  const json = JSON.stringify(ticket);
  console.log(json);
  // json = {"isValid":true,"price":2000,"cityFrom":"MSK","cityTo":"SPB","date":"2024-06-27T10:05:33.522Z"}
  // Здесь мы встречаемся с первым моментом. Видно, что не все упаковалось, функцию мы уже потеряли.

  const parsedObject = JSON.parse(json);
  console.dir(parsedObject);
  // {
  //     isValid: true,
  //     price: 2000,
  //     cityFrom: 'MSK',
  //     cityTo: 'SPB',
  //     date: '2024-06-27T10:05:33.522Z'
  // }

  testTypes(parsedObject);
  //   Если проверить типы, что мы увидим, что дата теперь не объект, а строка.
  //   isValid boolean
  //   price number
  //   cityFrom string
  //   cityTo string
  //   date string
}

{
  const json = JSON.stringify(ticket, ["isValid", "price", "cityFrom", "date"]);
  console.log("json:", json);
  // json: {"isValid":true,"price":2000,"cityFrom":"MSK","date":"2024-06-27T11:18:08.648Z"}
  // Проблема с датой осталась, но мы
  // можем фильтровать нужные данные для передачи

  // JSON.parse с функцией восстановления
  const recoveredObject = JSON.parse(json, function (k, v) {
    if (
      typeof v === "string" &amp;&amp;
      /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(v)
    ) {
      return new Date(v);
    }
    return v;
  });

  console.dir(recoveredObject);
  //   {
  //     isValid: true,
  //     price: 2000,
  //     cityFrom: 'MSK',
  //     date: 2024-06-27T11:24:24.112Z
  //   }

  testTypes(recoveredObject);
  // isValid boolean
  // price number
  // cityFrom string
  // date object
}
</code></pre>



<p></p>
<p>Сообщение <a href="https://consultapp.ru/interesting-moments-in-json-stringify-parse-in-javascript/">Некоторые тонкости методов JSON stringify и parse в JavaScript</a> появились сначала на <a href="https://consultapp.ru">ConsultApp.ru</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Pre-loader для сайта</title>
		<link>https://consultapp.ru/pre-loader-for-site/</link>
		
		<dc:creator><![CDATA[Дмитрий]]></dc:creator>
		<pubDate>Sun, 05 May 2024 10:00:40 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://consultapp.ru/?p=1891</guid>

					<description><![CDATA[<p>Как показать предзагрузку сайта до загрузки каких-либо скриптов и полного HTML документа?</p>
<p>Сообщение <a href="https://consultapp.ru/pre-loader-for-site/">Pre-loader для сайта</a> появились сначала на <a href="https://consultapp.ru">ConsultApp.ru</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>В данной статье мы рассмотрим, как показать информацию о процессе загрузки сайта до самой загрузки каких-либо скриптов и полного HTML документа.</p>



<span id="more-1891"></span>



<p>Наша задача каким-то образом показать элемент на странице, до загрузки чего бы то ни было тяжелого вроде скриптов, как минимум полной загрузки <strong>&lt;body&gt;</strong>, а потом отследить загрузку и убрать этот элемент. На первый взгляд это кажется противоречащим самому себе. Как показать что-то, до загрузки части документа, который как раз и содержит визуальную информацию и убрать после? </p>



<p>Однако есть один момент. Теги<strong> &lt;html&gt;</strong>, <strong>&lt;head&gt;</strong> читаются раньше, плюс в CSS есть псевдоэлементы, нас интересует <strong>::before</strong>. </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Псевдоэлементы <strong>::before</strong>, <strong>::after </strong>— это часть селекторов<strong>&nbsp;</strong><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements">CSS</a>, которые используют для вставки содержимого, которого нет в исходном коде.</p>
</blockquote>



<h2 class="wp-block-heading">Решение</h2>



<ol class="wp-block-list">
<li>Добавляем стилизованный псевдоэлемент <strong>::before</strong> на тег <strong>&lt;html&gt;</strong> с нужным нам элементом-прелоадером;</li>



<li>Отлавливаем в JS момент загрузки страницы (2 варианта). Убираем отображение загрузки, с помощью добавления класса конца загрузки тегу <strong>&lt;html&gt;</strong>.</li>
</ol>



<h2 class="wp-block-heading">Подробное описание</h2>



<p>Рассмотрим пример добавление прелоадера  на примере нашего сайта. </p>



<p>Добавляем в <strong>&lt;head&gt;</strong>, напрямую или через файл, стили:</p>



<pre title="style.css" class="wp-block-code"><code lang="css" class="language-css line-numbers">html::before {
  background-size: 150px !important;
  opacity: 1;
  content: "";
  display: block;
  position: fixed;
  z-index: 999;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: url("/logo-animate.svg") no-repeat center, #fff;
  transition: opacity 0.3s ease-in;
}

html.loaded::before {
  opacity: 0;
  pointer-events: none;
}</code></pre>



<p>Здесь видно, что в нашем случае <strong>content</strong> &#8212; пустая строка. Мы позиционируем по центру <strong>background</strong> с SVG лоадером, растягивая слой на весь экран, а так же выставляя большой <strong>z-index</strong>, что позволит нам скрывать постепенную загрузку/отображение элементов. Плюс небольшая анимация перехода.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img decoding="async" src="/logo-animate.svg" alt="/logo-animate.svg - background с SVG лоадером" style="width:150px"/><figcaption class="wp-element-caption">Файл /logo-animate.svg</figcaption></figure></div>


<p>Далее у нас есть 2 варианта работы с JS, мы можем поймать события:</p>



<ul class="wp-block-list">
<li><strong><code>DOMContentLoaded</code></strong>&nbsp;– браузер полностью загрузил HTML, было построено DOM-дерево, но внешние ресурсы, такие как картинки&nbsp;<code>&lt;img&gt;</code>&nbsp;и стили, могут быть ещё не загружены;</li>



<li><strong><code>load</code></strong>&nbsp;– браузер загрузил HTML и внешние ресурсы (картинки, стили и т.д.).</li>
</ul>



<p>Выбор за Вами, понятно, что первое событие будет раньше и Вы можете даже добавить дополнительный этап загрузки, между <strong>DOMContentLoaded</strong> и <strong>load</strong> соответственно. Мы же остановимся на load:</p>



<pre title="script.js" class="wp-block-code"><code lang="javascript" class="language-javascript line-numbers">window.addEventListener("load", () =&gt; {
  document.documentElement.classList.add("loaded");
});

setTimeout(()=&gt;{ 
    if(!document.documentElement.classList.contains("loaded"))
       document.documentElement.classList.add("loaded");
}, 10000);</code></pre>



<p>Объекту <strong>window</strong> добавляем событие <strong>load</strong>, по которому добавляем класс окончания загрузки на тег &lt;<strong>html</strong>&gt; (в JS к нему можно обращаться как к documentElement). </p>



<p>Так же, для очень медленных соединений, мы посчитали необходимым снимать loader (setTimeout) через 10 сек, после загрузки скрипта, если DOM дерево по каким-то причинам будет очень долго строиться и отображаться. Что-бы показать хоть какой-то процесс или возможно наличие обрыва соединения.</p>



<h2 class="wp-block-heading">Упаковка в plugin WordPress</h2>



<p>Для удобства управления, все вышеописанное можно упаковать в плагин WP. Например такой код позволит подключить стилевой и скриптовый файлы:</p>



<pre title="easy-page-preloader.php" class="wp-block-code"><code lang="php" class="language-php">&lt;?php
/*
Plugin Name: Easy Page Preloader
Plugin URI: http://consultapp.ru/pre-loader-for-site/
Description: Adding a preloader to the pages. No conflicts with SEO. You can set your own logo.
Version: 1.0
Author: Dmitry Egorov
Author URI: http://consultapp.ru/
License: GPLv2
*/

//********************************************************************
//*************************** PLUGIN CORE ****************************
//********************************************************************

function ca_epl(){
        wp_enqueue_style( 'html-loader', plugins_url( '/style.css', __FILE__ ) );
        wp_enqueue_script( 'html-loader-script', plugins_url( '/script.js', __FILE__ ), array(), '1.0.1', true );
}
add_action('wp_enqueue_scripts', 'ca_epl');</code></pre>



<h2 class="wp-block-heading">Заключение</h2>



<p>В статье мы рассмотрели, как с помощью прсевдоэлемента <strong>::before</strong> добавленного к тегу <strong>&lt;html&gt;</strong> добавить <strong>preloader</strong> на страницу, и отключать его по событию <strong>load</strong> на объекте <strong>window</strong>.</p>
<p>Сообщение <a href="https://consultapp.ru/pre-loader-for-site/">Pre-loader для сайта</a> появились сначала на <a href="https://consultapp.ru">ConsultApp.ru</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
