Проблема в моменте с await items.map(...)
т.к. map возвращает массив - а не промис - то никакого ожидания не происходит. Можно как посоветовали выше не использовать .map, или воспользоваться Promise.all:
let result = await Promise.all(items.map(async (item) => {}))
На вкладке performance в chrome dev tools можно смотреть сколько времени выполняется конктретный кусок кода, на вкладке memory можно делать снапшоты, там так же будет статистика по каждому типу объекта
Поведение как раз не странное. Вот что бывает, когда над итерируемым объектом совершают какие-то преобразования.
div.children - это NodeList, вы его меняете внутри forEach, и сбиваете итератор тем самым.
Чтобы этого не происходило нужно получить объект класса Array и выполнять итерацию уже по нему.
Чтобы это сделать можно использовать либо Array.from, либо Array.prototype.slice.call(div.children)
А почему канвас? На svg как правило все намного проще, особенно если нужна какая-то интерактивность. Если хочется уже готовое - смотреть в сторону того, что посоветовал JRK_DV, если хочется писать свое - то d3.js
Делаете docker-compose файл, в котором поднимаете контейнеры со всеми нужными сервисами (DB, API,..., selenium/что угодно).
Делаете контейнер, который маунтит папку с тестами в себя и запускает их
Тогда тесты будут запускаться грубо говоря одной командой docker-compose up %название_сервиса%
В CI это можно запускать так же (по крайней мере в travis / jenkins)
Про хранение - логичнее всего держать это в отдельной репе, если фронт и разные API находятся в разных репозиториях, это же не тесты фронта.
сохранить из канваса в вектор не получится, канвас - это растровое изображение. Для получения растрового изображения(png/webp) можно использовать метод toDataURL
1 - нарисуйте картинку для одномерного случая. Градиент превратится в обычную производную. Производная - это угол наклона касательной к нашей cost функции. Получается на этом шаге мы смотрим возрастает функция или нет (производная больше или меньше) и в зависимости от этого смещаемся в сторону, где функция меньше на размер шага(отсюда и название - градиентный спуск, мы спускаемся к минимуму функции используя градиент как направление). Для многомерного случая все так же, мы по сути делаем это для каждой переменной.
2 - чтобы не попасть на локальный минимум
На input вешаете ngChange, и слушаете изменения. Желательно с ng-modeloptions={debounce: '500'} хотя бы, чтобы не дергалось всё после каждого ввода.
В обработчике изменения простой Array.filter с нужными параметрами.
Можно это сделать и через filter, но мне такой вариант не очень нравится.
Если вы это в ng-repeat потом пихаете - то стоит trackBy поставить какой-то кастомный.
Ну и вообще 1. angular.merge deprecated, 2. вызывать его для мержа массивов - какая-то жесть
Что, если добавлять mousein событие с capture=true и preventDefault? Вариант с дивом вызовет те же самые операции с обновлением слоев и пересчетом стилей.