Pull to refresh
16
0
Dmitry @Riim

User

Send message

Ок, теперь я понимаю вашу логику)) Безусловно она есть, но в ней остаётся проблемка: Object.assign можно считать точно присутствует, тк. здесь про веб-компоненты и заменять его на работающий неправильно будут только из чистого вредительства и этому бесполезно сопротивляться, захотят нагадить -- нагадят. А вот добавлять что-то в Object.prototype могут из самых ярчайших побуждений. Причём сталкивался я с этим буквально с пол года назад пробуя какую-то либу для тестов, название уж не помню, но вроде что-то достаточно популярное было. Так что всё ещё встречается такое дело, такова пока реальность и с этим нужно как-то жить.
Давайте так, мы тут оба по-своему правы, оба привели сильные аргументы и хорошие аналогии. И, наверняка, оба мы в реальной жизни используем Object.(keys|values|entries) + for-of|forEach, что как бы совсем закрывает вопрос с необходимостью в hasOwn-проверке. Так что смысла в дальнейшем споре никакого нет и ни во что доброе он при продолжении не превратиться. Предлагаю на этом закончить. Приятно было пообщаться с умным человеком, хорошего вам дня!

Извините, но я не понимаю вашей логики. Вы предлагаете надеяться, что там где будет использоваться компонент в Object.prototype всё будет чисто, вместо того чтобы писать код который будет гарантированно работать вне зависимости от этой чистоты? Нахрена?! Вам лишнюю строчку сложно написать, так используйте Object.keys|values|entries в которых эта проверка уже встроена:

for (let key of Object.keys(obj)) {
    // ...
}

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

если вы что-то добавляете в Object.prototype

да где я написал, что я что-то туда добавляю? Там же чёрным по белому написано:

будет запускаться на чужих проектах где кто-то очень умный мог нагадить в Object.prototype

Так можно сказать если писать этот редактор только для своих проектов, но автор ведь делиться им и значит предполагает, что он будет запускаться на чужих проектах где кто-то очень умный мог нагадить в Object.prototype. Так что hasOwnProperty всё же совсем не лишний)

Так себе совет. Как минимум в предлагаемом варианте нужна hasOwn-проверка, как максимум есть for-of (в сочетании с Object.entries), очень неплохо поддерживаемый браузерами имеющими поддержку веб-компонентов, то есть целевыми.

UPD: на счёт максимума ошибся, Object.assign предлагаемый ниже ещё лучше :)

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

Один в один повторён пассивный режим вычисления из cellx, тот же глобальный счётчик, та же возможность лишних вычислений при тех же условиях и у меня даже то же самое оправдание для них)). На сколько я помню cellx в этом режиме действительно прилично так быстрее, чем в основном, но у меня этот режим скорее как костыль для автоматической финализации (dispose) ячейки при удалении последнего подписчика, в акте же этот режим удалось сделать основным, что тут сказать, отличная работа проделана!

UPD: а вообще смотрю я как используются reactions в коде cellx-а и понимаю, что отказаться от получаемого таким образом функционала будет очень больно, функционал тут для меня определённо важнее скорости.

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

Если не хочется ставить в конце, то можно заметно реже ставить в начале, при определённых правилах всё будет 100% без проблем, вот здесь можно почитать: https://standardjs.com/rules.html#semicolons

Делал что-то подобное для Decimal.js, сложные записи на котором в некоторых местах совсем уж тяжко стало читать, а производительностью можно было пожертвовать в пользу читабельности. Но я пошёл чуть другим путём -- использовал tagged template literals, в простейшем случае это выглядело примерно так:

big`(${x} + ${y}) * ${z}`

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

На одном из собеседований по приёму на работу попросили за 30 минут написать программу

Задачка, конечно, интересная, но по мне так идиотизм давать такое на очном собесе ещё и с ограничением по времени. Даже сильный специалист банально из-за волнения может затупить с вероятностью 50/50. Результат будет совершенно не показательный, зато уверенно пройдёт отлимпиадник с нулевым опытом реальной разработки. Если такой и нужен, то ок конечно, но по мне так лучше давать несколько мелких, но хитрых задачек по 3-7 минут на каждую и смотреть по кол-ву решённых. Причём, начинать нужно с наиболее лёгких -- сбить волнение.
Говорю это на собственном опыте, на одних собесах без проблем решал подобное, особенно когда вакансия не особо интересна и больше по приколу собес проходишь, на других начинаешь чуть тупить, из-за этого волнуешься, от волнения ещё больше тупишь и так по кругу. Результат околонулевой, после собеса уже спокойно садишься и через 15 минут получаешь рабочее решение. Только работодатель уже не поверит, что я его сам получил, а не в интернете нашёл.
Хороший пример с Яндексом, куда я дважды устраивался. Первый раз собеседующий начал закидывать меня мелкими задачками, каждая легко решалась знанием какой-то фичи языка, но можно было и без этого обойтись. В конце он сказал, что я первый кто всю его коллекцию успел решить, большинство около трети решают. При втором устройстве было два коротких собеса минут по 30-40 и задачи уже явно больше, хоть и не как в статье. На первом решил две, на втором первую и жёстко затупил на второй. В результате два собеса с хорошим результатом и один с плохим. Так это точно не должно работать.

А вот как сделать драг-н-дроп в cellx или $mol я совсем не понимаю

ОРП реализации из статьи заточены в первую очередь на использование в стейт-менеджерах, для обработки пользовательского ввода нужно будет самому дописать некоторые вещи идущие в RxJS из коробки. С другой стороны RxJS не очень годится для использования в стейт-менеджерах, т.к. в основе стримы вместо атомов/ячеек и это создаёт дополнительные трудности, порой довольно неприятные.
Набросал простейшую реализацию dnd на cellx, она конечно не идеальна, но как пример вполне сгодится: https://riim.github.io/cellx/docs/examples/simple-dnd.html .

fnCall создаётся внутри производной функции, во-первых, создавать его (fnCall) на каждый её (производной функции) вызов нет необходимости, во-вторых, так в таймаут попадает первая созданная функция, которая запомнила первые this и args, а нужны последние.
По ссылке в моём комменте выше есть рабочий вариант. Или вы пробуете самостоятельно сделать?

(...args) => {
...
lastThis = this;

this будет от внешней функции, у стрелочной нет своего, а здесь как раз нужно запоминать this производной функции. Тоже самое для debounce.

Для throttle clearTimeout внутри setTimeout не имеет никакого смысла.

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

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

Для debounce то же есть хорошее улучшение. Допустим происходит 100 вызовов производной функции и задержка между ними всегда меньше wait, то есть вызов исходной функции произойдёт только 1 раз. В вашей реализации будет создано 100 таймаутов из которых 99 будут отменены и 1 сработает. Можно улучшить реализацию следующим образом: при первом вызове создаётся таймаут, при втором он не отменяется, а вместо этого просто обновляется время последнего вызова производной функции, таких вызовов до срабатывания таймаута может произойти несколько, дольше вызывается таймаут и в нём видя, что время последнего вызова обновилось не вызывается исходная функция, а создаётся следующий таймаут на время `wait - (Date.now() - timestamp)`. Таким образом количество создаваемых и отменяемых таймаутов сильно падает, иногда в десятки раз при том же конечном результате.

Грамотные реализации этих двух функций не так уж тривиальны как кажется на первый взгляд. Несколько лет назад используя одну из популярных реализаций throttle с npm столкнулся со странным поведением, полез разбираться в исходники, баг нашёл, а заодно ещё один. Полез смотреть исходники других вариантов, просмотрел всю первую страницу выдачи npm и почти во всех пакетах удалось найти минимум один полноценный баг. В тот момент стало очень грустно от качества кода на npm. Запилил свои реализации: @riim/debounce-throttle , на идеальность не претендую, но делал очень вдумчиво и думаю качество всё же повыше среднего на npm.

Я учился ковыряя чей-то парсер, там довольно хороший пример был, но сейчас мне его уже не найти. Попробуйте поковырять мои парсеры. Вот этот тыц парсит биндинги в текстовых нодах вроде таких text {key.path.to.date |fdate('DD.MM.YYYY') |or('\u2014') } text. Кода многовато из-за возможности разбирать в тч. такие конструкции |formatter({key:[,,{'key':/r\\\e/g,},,]}), то есть любая вложенность объектов/массивов, висячие запятые и пустые значения в массивах, ключи с кавычками и без, регулярки, экранирование в строках и регулярках, спецсимволы и тд… Ещё один парсер тыц, парсит вот такое дело: https://i.imgur.com/7O07D0F.png .

Тогда парсер споткнется о запятые

С чего бы? Я про нормальный парсер, а не про сплит по запятым.

Я там уже добавил обновление в свой коммент выше)).

Для передачи вниз контекст прекрасно подойдёт, а вот для передачи вверх без создания жёсткой связи он мне кажется малопригоден.


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

Проксирование через десятки компонентов вниз

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


UPD: глобальным объектом в этом случае обычно делается корневой компонент приложения который виден из всех компонентов как this.ownerComponent (или this.rootComponent).

Описанный подход создаёт жёсткую связь от подчинённого компонента к владеющему компоненту. Нормально в обратном направлении — владелец вызывает метод подчинённого, причём для этого не нужен какой-то глобальный объект, ведь владелец знает своих подчинённых, если же подчинённый лежит в каком-то компоненте-обёртке, то на нём (компоненте-обёртке) создаётся проксирующий метод. В описанном же варианте периодически будут возникать ситуации, когда казалось бы универсальный компонент перемещается в другое место с полным удалением бывшего владельца и от этого ломается. Правильный подход — использование всплывающих событий — подчинённый компонент просто эмиттит событие о том, что с ним случилось, если какому-то предку вверх по иерархии нужно как-то на это реагировать, он подписывается на это событие. Куда бы не перемещался подчинённый компонент, он не ломается, тк. связь не жёсткая. Если два компонента никак не вложены друг в друга и всё равно должны взаимодействовать, то взаимодействие делается через общего для обоих предка, который подписывается на событие одного компонента и вызывает метод другого.

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

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity