Войдите или зарегистрируйтесь
Вы сможете писать комментарии и посты, ставить лайки и другое
Поиск
Тёмная тема

Посты по тегу: IT

Неочевидно опасное undefined behaviour в языке Си

19 дн. назад
Чтобы мозг не раскисал, учу Си. Язык простой и одновременно довольно сложный. А ещё в нём есть куча undefined behaviour - неопределённое поведение компилятора для пограничных случаев, которых на самом деле масса.

Вот пример простейшей функции:
int get_zero(void) {
  int num;
  return num & 0;
}
Переменная num не инициализирована, значит там могут сидеть любые "мусорные" биты.
& - это оператор побитового И, который сравнивает последовательно биты двух чисел и ставит в соответствующий бит возвращаемого числа 1, только если оба бита - это 1, иначе поставит туда 0.

Вроде всё просто и кажется, что функция всегда должна вернуть 0, ведь "побитовый и" с нулём всегда вернёт ноль.
123 // 00000000 00000000 00000000 01111011
0   // 00000000 00000000 00000000 00000000
Сравнение битов двух чисел выше всегда вернёт 0, т.к. второе число тоже 0. Неважно, какие там будут биты у первого числа, всегда в итоге 0.

Но проблема кода здесь связана со спецификацией Си. Код небезопасен, потому что теоретически компилятор может делать всё что угодно! Программа может "упасть", компилятор может удалить код и прочее. Компилятор имеет право делать что угодно в этом случае. Undefined behaviour - это поведение программы, для которого стандарт языка не накладывает никаких требований, стандарт не говорит, что должно или не должно произойти!

Т.е. писать код таким образом в Си - опасно. Даже переполнение обычного signed int (он же просто int) в Си - это уже undefined behaviour!
int x = 2147483647; // Максимальное значение
x = x + 1; // Опачки - undefined behaviour - рисково!
Вот такое приходится учить. А кто-то жалуется на сложности Golang.
+2
73

Внимание владельцам сайтов: Gmail почта позволяет создавать дубликаты аккаунтов в огромных количествах

недавно
На многих сайтах регистрация аккаунта осуществляется через email-адрес. Одно мыло - один аккаунт, вроде всё просто. Если забанить такого пользователя, то он не сможет зарегистрироваться снова на тот же самый email. Но это теоретически.

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

Допустим есть пользователь c такой гугловской почтой:
vasya.pupkin.example@gmail.com
Если поменять регистр букв в имени юзера и отправить письмо на:
Vasya.PUPkin.example@gmail.com
то ему придёт письмо в настоящий ящик!

Сколько таких комбинаций возможно? Очень много!

Мало того, можно подобавлять точки в адрес:
va.s.ya.pu.p.k.in.example@gmail.com
и ему тоже придёт письмо в ящик-оригинал.
Даже если убрать точки из оригинала:
vasyapupkinexample@gmail.com
то письмо тоже придёт!

Представьте, сколько десятков тысяч комбинаций можно сделать с точками и изменениями регистра букв. Можно насоздавать тысячи вредительских аккаунтов, если сайт не защитился от этой "фишки" гуглопочты. Банить устанешь.
+2
89

ChatGPT 5 - туфта, не заменит программистов (реальный пример на Nuxt 4)

недавно
OpenAI зарелизили ChatGPT 5 - очередную самую крутую модель своей нейросети. А что в итоге?
Мой промпт:
Я делаю build nuxt 3 / nuxt 4 приложения.
Как понять в какие чанки какие файлы залезли?
Почему чанки такие большие?

До этого спрашивал у 4-ки - предлагал ставить vite-bundle-visualizer. Сразу говорю - это не надо делать, всё уже есть встроенное. Сегодня появилась возможность спросить у 5-ки - повторно спросил. Пятый ChatGPT опять предлагает поставить пакет, на этот раз rollup-plugin-visualizer.

Окей, пытаюсь добиться у него информации, которая должна по моему мнению быть показана в ответе (CLI команды), ChatGPT 5 выдаёт:
Пытаюсь узнать про "npx nuxi analyze", он ищет в интернете и долго думает и всё равно выдаёт:
Показать полностью...
+1
16

Весы с машинным зрением в Перекрёстке

недавно
В нашем городе опять технологическое чудо. К кассам самообслуживания все уже привыкли, но вот умные весы впервые поставили.
Показать полностью...
+2
11

Наконец-то купил себе лавандовый раф

недавно
Я айтишник. Тот самый айтишник, быть которым так модно стало в последние 5 лет. Хотя в самом IT я уже много-много лет с нулевых годов.

Так вот за свою жизнь я ни разу не пил лавандовый раф, хоть и айтишник (терпеть не могу такое название программистов). Исправился, купил.
Показать полностью...
+2
16

Nuxt продан: Vercel, который владеет Next.js, теперь владеет и главным SSR-фреймворком для Vue

недавно
Новость пришла откуда не ждали: монополизация во фронтенде - Vercel купил Накст. Они и так владели Некстом (главным SSR-фреймворков для Реакта), а теперь у них руки добрались и до вьюшной экосистемы.

Об этом сообщил создатель NuxtJS - Daniel Roe (ник danielroe на Гитхабе). Чисто теоретически Накст остаётся независимым, а Vercel купил только NuxtLabs, а также нанял себе ключевых разработчиков Накста. А практически - у них теперь Nuxt и они теперь будут задавать направление развития.

Не знаю, хорошо это и плохо, но монополизация - это точно плохо.
+2
89

Популярность Vue.js в России в 2025 году

недавно
В комментах на ютубе поспорил о популярности Vue JS. Мне доказывали, что балом правит Реакт, а Vue где-то на задворках. Увы, реакт-разработчики варятся в своём котле и не видят текущих тенденций. А текущая тенденция такова, что в России Вьюха постепенно откусывает кусок у Реакта.

Для анализа выбрал тематику недвижимости - застройщики. Список крупнейших застройщиков России в 2025 году, данные с Домклика, по количеству сделок:
1. ПИК
2. Самолет
3. ЮгСтройИнвест
4. Холдинг Setl Group
5. ССК
6. Страна Девелопмент
7. ГК ФСК
8. Гранель
9. ЛСР
10. DOGMA
11. АКВИЛОН
12. Домостроительный комбинат
13. ГК Кортрос
14. Талан
15. ГК "А101"
16. ЭНКО
17. Брусника
18. ГК Расцветай
19. GloraX
20. DARS Development
Смотрим сайты:
pik.ru - React
samolet.ru - Vue
gk-usi.ru - другое
setlgroup.ru - Vue
sskuban.ru - Vue
strana-development.ru - другое
fsk.ru - Vue
granelle.ru - Vue
lsr.ru - React
dogma.ru - React
group-akvilon.ru - Vue
dsk1.ru - Vue
kortros.ru - Vue
ижевск.талан.рф - Vue
a101.ru - Vue
enco.ru - другое
moskva.brusnika.ru - Vue
гкрасцветай.рф - другое
glorax.com - Vue
dars.ru - React

Ну как вам? Реакт - 4 сайта, VueJS - 12 сайтов. Сам не ожидал таких результатов, тут Вью опережает Реакт в 3 раза! Но обычно примерно 50/50 или даже чуть больше у Реакта.

Единственная сфера деятельности в России, где засилье Реакта - это банки. Так сложилось по историческим причинам, там началось всё с Реакта и остальные банки стали как обезьянки повторять и ставить себе Реакт тоже.

Многие React-разработчики просто не пробовали что-то другое. Я пробовал React, я пробовал Vue и сделал свой выбор в пользу второго. Стоит начать писать код на Vue и к React-у не захочется возвращаться.
Показать полностью...
+2
61

How to use Quill Editor with Nuxt 3 and SSR (Vue)

недавно
If you try to use Quill Editor with Nuxt 3 when rendering a page in SSR you will get this error:
500 document is not defined.
That means NodeJS doesn't have the global variable 'document'. Because SSR rendering is executed in
a NodeJS environment, not a browser.

The sad fact: <client-only> won't help with this problem. The problem with quill's code is that during import, it assumes it's being executed in the browser. I hope you remember that the code imported from the module is not just imported, but executed, i.e. the authors of Quill wrote it so that the 'document' object is immediately accessed there. Very bad.

One solution is to disable SSR, but its an awful solution. But the second solution is to use dynamic JS imports.

My <script lang="ts" setup> in QuillEditor.vue in Nuxt 3 project:
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
// import Quill from 'quill'; // SSR problem with 'document', need to use dynamic import
import type Quill from 'quill';

const elemForQuillEditor = ref<HTMLDivElement|null>(null);

let editor: null|Quill = null; // Do not store in ref() - it causes bugs!

// ...

async function createQuillAndSetListeners() {
  const Quill = (await import('quill')).default; // This is most important thing - usage of JS dynamic import

  if (!elemForQuillEditor.value) return;
  editor = new Quill(elemForQuillEditor.value, {
    theme: 'snow',
    modules: {
      history: {
        delay: 2000,
        maxStack: 500,
        userOnly: true,
      },
      toolbar: {
        container: [
          ['bold', 'italic', 'underline', 'strike'],
          ['link'],
          [{ list: 'ordered' }, { list: 'bullet' }],
          [{ script: 'sub' }, { script: 'super' }],
          [{ header: [1, 2, 3, 4, 5, 6, false] }],
          [{ color: [] }, { background: [] }],
          ['clean'],
          ['undo', 'redo'],
        ],
        handlers: {
          undo() {
            editor?.history.undo();
          },
          redo() {
            editor?.history.redo();
          },
        },
      },
    },
    placeholder: props.placeholder,
  });
  
  editor.on('text-change', () => {
    if (!editor) return;
    // ... my other code
  });
}

// ...

onMounted(createQuillAndSetListeners);

Now your Quill editor will work in Nuxt 3 even during SSR!
+2
39

Как по-английски костыль в программировании

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

В английском языке принято говорит "workaround", т.е. обходной путь. Но этот термин не несёт смысловой нагрузки, которую в русском языке означает костыль. Костыль - это значит код можно заменить нормальным кодом, это значит, что разрабу даже немного стыдно за код, но поделать пока ничего нельзя. А workaround - это более мягкий термин, этакий хак для достижения цели.

Так вот на английском языке есть аналогичное слово - kludge (кладж). Смело используйте его в своих слаках и гугл-митингах, когда общаетесь на английском. Никаких больше workaround, теперь только честный kludge!
+3
161

Хитрость spread-синтаксиса в JS

недавно
А вы знали, что теоретически spread-синтаксис в JS можно применять почти к любому типу.
Вот пример "обычного" использования:
// Массив спредится
console.log([...[1, 2, 3]]); // [1, 2, 3]
// Строка спредится
console.log([...'Famabara']); // ['F', 'a', 'm', 'a', 'b', 'a', 'r', 'a'] 
Но если попытаться заспредить number, то будет ошибка:
console.log([...555]); // Uncaught TypeError: 555 is not iterable
Не является iterable.
Так давайте сделаем iterable!
Number.prototype[Symbol.iterator] = function * () {
  yield 'Фамабара';
  yield 'лучше';
  yield 'всех';
}

console.log([...555]); // ['Фамабара', 'лучше', 'всех']
Мы успешно заспредили number! Толку от этого никакого, на сам факт забавен.
Можно джунов за собесах мучить :)
+4
131

Firefox не чинит баг уже 13 лет

недавно
На Famabara появилась возможность перетаскивать мышкой части формы поста, если лень сортировать кнопками вверх/вниз. И, оказалось, что эта функция не работает в Firefox.
Багу 13 лет!!! Вы когда-нибудь видели, чтобы у популярного продукта не чинили баг столько времени? Пожалуйста:
https://bugzilla.mozilla.org/show_bug.cgi?id=739071

Если у предка стоит атрибут draggable="true", то клик мышкой по <textarea >или по <input type="text"> не позволит сфокусировать нормально в нужном месте текста. Мигающий промт возникнет или в начале текста или в том месте, где уже был до блюра.

<div draggable="true">
  <input value="Кликните в середину текста" type="text" />
</div>

Ну это совсем позорище! Багу поставили Priority: P3 и Severity: S3 (типа неважные вещи), а все дублирующие баг-репорты закрывают уже в течение 13 лет.

Есть одно решение, найденное в схожем багрепорте FF, но для contenteditable="true" - надо зажать Alt и кликнуть. Удобно, да? :)
+2
84

Как в Git безопасно поправить коммит в удалённой (remote) ветке

недавно
Представим вы несколько дней работали, писали код и наконец-то сделали коммит:
git commit -m "#715 changed color of button from red to green"
git push
И тут вы понимаете, что забыли убрать какой-нибудь console.log() или fmt.Println().
Можно добавить ещё один коммит поверх, что-то вроде:
git commit -m "#715 clean unnecessary code"
Но в некоторых командах это могут посчитать мусорным коммитом. Что делать?

Вместо второго коммита "правим" первый коммит, дописывая amend:
git commit --amend -m "#715 changed color of button from red to green"
И теперь можно пушить снова. Но сервер не даст запушить, ведь у нас локально и на ремоуте уже разные истории одной ветки. Можно запушфорсить:
git push force
Но это может быть очень плохо, если над веткой работает несколько человек. Кто-то мог уже поверх нашего коммита свои коммиты накатать. Но есть хороший параметр force-with-lease, который перезапишет ветку только тогда, когда никто поверх не дописал свои коммиты:
git push --force-with-lease
В этом случае никто не пострадает.
+3
68

TypeScript скоро станет в 10 раз быстрее

недавно
Андерс Хейлсберг (автор Тайпскрипта) опубликовал пост в блоге:
https://devblogs.microsoft.com/typescript/typescript-native-port/

В общем, TypeScript скоро станет в 10 раз быстрее, вернее, он уже стал таким, просто пока эту версию не сделали общедоступной.

Вот такой прирост скорости компиляции крупных проектов теперь показывает tsc:
Как видно, прирост на порядок - т.е. примерно в 10 раз. Достигается это за счет использования Golang для работы tsc, а не JS. Сам по себе JS быстрый, но он упирается в один поток. А кто писал на Go, то знает, насколько легко там запустить горутину. Теперь tsc будет использовать несколько имеющих потоков, что и даст прирост скорости компиляции.

Обратите внимание, это полноценная работа tsc, а не как у esbuild, где только транспиляция без проверки типов.

На момент написания этого поста текущая версия TypeScript - 5.8.2. Следующая мажорная версия - 6-я - будет всё ещё на JS-е, а вот 7-я версия будет уже на "нативном" коде, т.е. компилироваться из Go. Автор их так и называет:
For the sake of clarity, we’ll refer to them simply as TypeScript 6 (JS) and TypeScript 7 (native)

В общем, новость хорошая. Быстрее будет не только компиляция в JS, то и VSCode будет работать быстрее, потому что там все подсказки в редакторе, даже если это JS-код, реализованы с помощью тайпскрипта.
Показать полностью...
+3
136

Чем плох фриланс для разработчика?

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

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

И что вы думаете? Он вообще не умеет работать в команде. Он не задаёт вопросов, когда 100% нужно задавать вопросы. Всё делает сам и в своём стиле и потом мы разгребаем на код-ревью его код. Это раздражает. Если бы сначала спрашивал, то не было хотя бы велосипедов и всякой мути.

И вторая проблема вытекает из первой проблемы: качество его кода очень плохое! Человек все время варился в своем коде, он не умеет работать в команде и не знает, что код должен быть поддерживаемым другими людьми. Часть проблем решается линтером, но многие его подходы к решению проблем просто ужасают.
+5
160

Иногда position: fixed может не работать

недавно
Я матёрый веб-разраб, но иногда офигеваю, когда узнаю, что-то новое среди банальных вещей, которые по идее уже знаю больше десяти лет. Сейчас речь о CSS.

Вот вы знали, что position: fixed может не работать в некоторых редких случаях? Если у любого (!) предка задано, например, свойство transform, то всё, привет: блок с position: fixed уже привязывается не к вьюпорту. Хотя transform у элемента-предка мог быть задан всего лишь для сдвига какой-нибудь менюхи вбок или вообще для выравнивания position-absolute-блока по центру родителя. Но нет, уже не будет работать, таковы правила.

Аналогично ведут себя CSS свойства perspective, will-change или filter у любого из предка.

Век живи - век учись.
+4
103

Нужны ли курсы, чтобы вкатиться в IT?

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

Если вам нужны курсы, чтобы вкатиться в айтишечку, значит вы скорее всего не подходите для этой работы. Все есть в онлайне, гугли на здоровье и учись. А если ты не можешь найти нужные материалы, не можешь организовать себя для учебы, не можешь структурировать найденную информацию, то как ты работать собрался? За ручку тебя на работе никто водить не будет.

Мало того, реальная работа сильно отличается от того, что спрашивают на собесах (такая хрень, увы). Т.е. нужно учиться проходить собеседования и учиться работать. Это два связанных, но разных направления.

Поправка. Разговор о программистах. Про остальные IT профессии не скажу.
+3
98

RFC как стандарт

недавно
Многие программисты наверняка видели спецификации разных интернет-технологий под названиями RFC ***.
Например:
RFC 9112 - это спецификация для протокола HTTP/1.1
RFC 3629 - это спецификация для кодировки UTF-8

Так вот аббревиатура RFC означает Request for Comments, т.е. "запрос комментариев". Выглядит странно, да? Типа стандарт, но требует каких-то комментариев.

Оказывается, это так просто сложилось исторически. Изначально всё действительно обсуждалось и требовало комментариев. Т.е будущий стандарт прорабатывался путём долгих обсуждений умных дядек. И через некоторое время все спецификации/стандарты стали публиковаться под таким термином - RFC, хотя по факту никаких комментариев уже не требуется, ведь это уже официальный финальный документ. В общем, RFC
- это термин из 60-80-х годов и ныне полностью утратил свой изначальный смысл.
+3
94

Идёт разработка Vue Vapor

1 г. назад
Между прочим в мире VueJS большая новость - активно разрабатывается Vue Vapor. По основной идее этого проекта во VueJS исчезнет виртуальный DOM, который являлся важной частью всего VueJS. Теперь работа будет вестись напрямую с DOM и меняться будут только нужные HTML элементы, если срабатывает реактивность.

А еще интересная деталь: пишут, что будет работать только с Composition API, а Options API уйдёт на свалку истории. А ведь говорили, что этого не будет и старый Options API будет поддерживаться до последнего. Плюс обязателен script setup.
+3
170

Эффективность использования всех ядер процессора в NodeJS с помощью cluster

1 г. назад
Для повышения производительности приложений на NodeJS во всех материалах рекомендуется использовать нодовский встроенный модуль cluster. Все статьи повторяют одно и то же, что и так написано в документации.
Вот официальный пример из доки:
import cluster from 'node:cluster';
import http from 'node:http';
import { availableParallelism } from 'node:os';
import process from 'node:process';

const numCPUs = availableParallelism();

if (cluster.isPrimary) {
  console.log(`Primary ${process.pid} is running`);

  // Fork workers.
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  // In this case it is an HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}
А теперь поделюсь своими исследованиями и расскажу, что не так в этом примере и как это можно улучшить.

Во-первых, некорректен нейминг переменной numCPUs. На моём компьютере, на котором тестировал производительность, стоит процессор Intel i7-13700, в нём всего 16 ядер. Сайт Intel так и пишет:
Обратите внимание: 16 ядер и 24 треда. И нода после вызова availableParallelism() возвращает число 24, а не 16. Так что это не ядра, а треды.

Во-вторых, большинство нодовских приложений - это обычные API. Какой-нибудь REST API, гоняющий туда-сюда JSON. А берётся этот JSON в большинстве случаев из базы данных вроде PostgreSQL. Многие сайты, описывающие работу с модулем cluster в качестве примера, почему-то возвращают моковые данные, захардкоженные прямо в коде, а в реальную базу данных не лезут. И потом делают нагрузочное тестирование по этим данным. Т.е. при таком подходе на каждом ядре сидит по процессу NodeJS и другие процессы не мешают их работе, не заставляют переключать на себя внимание ядра.

А теперь давайте проведём тест на реальной работе REST API. Это будет GET-запрос за сущностью по её id. Чтобы сформировать JSON этой сущности, нода совершает не один, а несколько сложных запросов в базу данных. Кэширование в глобальных переменных или в Redis не используется.

Для тестирования я использовал пакет bombardier, написанный на Golang.
go install github.com/codesenberg/bombardier@latest

Сначала провёл тест на Windows 10.
Запускаю:
bombardier http://127.0.0.1:7100/api/some/1101
Результат без cluster:
Bombarding http://127.0.0.1:7100/api/some/1101 for 10s using 125 connection(s)
[=================================================================================================================] 10s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec      2754.89    1413.90    5813.88
  Latency       45.31ms     1.95ms    72.43ms
  HTTP codes:
    1xx - 0, 2xx - 27625, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:     9.99MB/s
Результат с cluster (все 24 потока):
Bombarding http://127.0.0.1:7100/api/some/1101 for 10s using 125 connection(s)
[=================================================================================================================] 10s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec      8424.89     801.49   15177.67
  Latency       14.84ms     1.69ms    72.64ms
  HTTP codes:
    1xx - 0, 2xx - 84224, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:    30.54MB/s
Разница по производительности почти в 3 раза.
Показать полностью...
+3
31

Передача по ссылке и передача по значению в JavaScript

1 г. назад
Насколько хорошо вы знаете JavaScript?
Как в JS передаются значения - по ссылке или по значению? Не спешите, подумайте даже если вы "мидл" или синьор-помидор.
let str1 = 'Famabara';
let str2 = str1; // Тут копия или новая строка?

let obj1 = { name: 'Famabara' };
let obj2 = obj1; // Тут копия или новый объект?

Можете в опросе ответить:
Как передаются значения при присвоении в переменную или в свойство объекта?
Теперь посмотрим, что нам говорит learn.javascript.ru - очень популярный в рунете учебник JavaScript:
А теперь давайте запустим в NodeJS такой код:
const arr = [];

for (let i = 0; i < 1200200; i++) {
  arr.push('0123456789'.repeat(1000 * 1000));
}

while (true) {
}

После запуска смотриим программой top потребление ресурсов:
39858 dima      20   0 2026180   1,0g  37824 R 100,0   3,2   0:21.44 node 
На моей Кубунте сожрано 1 Гб оперативки. Ух ты.

Теперь изменим немного код:
const arr = [];
const text = '0123456789'.repeat(1000 * 1000);

for (let i = 0; i < 1200200; i++) {
  arr.push(text);
}

while (true) {
}

Смотрим ещё раз через top:
40267 dima      20   0 1066148  73796  37440 R  99,7   0,2   0:12.27 node

Программа потребила всего 73 Мб вместо 1 Гб. Согласно популярной теории о копировании примитивов такого быть не должно. ;)

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

Кстати, на ноде в Windows 10 аналогичное поведение - около 1 Гб потребление против менее 100.

Ну, а теперь главный секрет! :)
В JavaScript всё передаётся/копируется по ссылке!
Показать полностью...
+4
87
1
2