因为我没有在Telegram的JavaScript开发人员竞赛中获得第一名

Telegram的活跃用户,尤其是那些订阅了Pavel Durov的用户,可能听说过Telegram在您的这些Internet站点上举行了针对iOS,Android和JavaScript开发人员以及设计师的竞赛这一事实。 尽管这是一次具有丰厚奖金分布的史诗般的活动(其中一名参与者获得了5万美元的奖金,并且编写了最快,最简单的Android应用程序),但他们至少在Runet上几乎不写任何东西。 我的处女作将尝试解决这种情况。


由于我是全栈JavaScript开发人员(准确地说是TypeScript开发人员),所以我决定进行自我测试。 马尼拉不仅是一项奖金,而且是格式本身:这不是一场编程比赛,在这场比赛中抽象性和思考速度至关重要。 复杂的一切在这里都很重要:经验,中期的开发速度,UI问题的品味,整个计算机科学的知识以及自我批评。 根据比赛的条款,有必要开发一个用于显示以下平台之一的图形的库:iOS,Android或Web。


不同平台的开发人员没有竞争,每个平台都有自己的赢家。 主要标准是:工作速度(包括在较旧的设备上),与设计的一致性,流畅的动画和最小的应用程序大小。 现有的解决方案和库已经无法使用,所有内容都必须从头开始编写。

在此之前,我参加了针对开发人员的竞赛,在竞赛中,所有任务的分配时间均不超过5个小时,这些时间不得不花很大的压力。 尽管Telegram并不需要那么费力才能完成任务,但这是我必须参加的最困难的比赛之一。 看起来似乎并不复杂的任务是如此之大,以至于如果我付了钱,我可以将这些“图形”裁剪几个月,试图在代码性能与其体系结构和谐之间找到折衷方案。 它为解决方案分配了三周( 最多 两周,感谢vlad2711的修正)。 一些竞争对手专门请假,以腾出更多时间参加比赛,我决定像往常一样在晚上和周末将比赛的发展与“ Ontanta ”的工作结合起来。

CANVAS与SVG


我们所有人面临的最重要的建筑问题是图形渲染工具的选择。 当前,网络标准为我们提供了两种方法:通过生成实时的svg图形和优质的旧画布。 这是各自的优缺点。

帆布


+绝对的多功能性-能够更改画布上任何像素的颜色,您可以绘制任何想要的东西。
+ [潜力]高性能-如果您可以准备画布,则可以显示出良好的性能。 使用webgl会很棒,但是它对智能手机的支持很差。

-所有计算和所有手工渲染-与SVG不同,折线的中间点可以设置一次,然后您可以操纵视图框沿折线的各个部分移动“相机”,使用画布,一切都变得更加复杂:这里没有“相机”,有仅从左上角开始的坐标; 如果需要“移动”图表的当前查看区域,则必须重新计算其所有点相对于查看区域的新位置的所有坐标。 换句话说,在svg中开箱即用的viewbox需要在canvas中手动实现。
-整个动画是手动的-在上一段的基础上,通过重新计算坐标,颜色和透明度值并每秒重绘整个场景第N次来实现所有可能的动画,并且重新计数和重绘场景的次数越多,动画就越平滑。

SVG


+简单渲染-只需将必要的线条,形状等添加到SVG中,即可通过操纵视口,颜色和透明度设置来浏览图形。
+动画的简单实现-再次基于上一段,Ne足以为视图框,颜色和透明度每秒指定新值,并且图像将自己重绘,浏览器将负责此操作。 另外,不要忘记SVG中的形状和基元可以在CSS中设置样式,因此可以使用CSS3动画对其进行动画处理,这为以最少的努力获得炫酷的动画提供了最大的可能性。
+默认情况下具有良好的性能-如果您可以轻松地在画布上放一些缓慢的东西并消耗数百个资源,那么基于SVG的结果将始终看起来非常轻巧,体面和流畅。

但是硬币有另一面。

-适度的优化机会-由于我们不是在绘制svg,而是在浏览器中绘制,因此无法控制此过程-如果您想提高性能(例如,已经缓存单个绘制的元素),则无法以任何方式进行。 这很可能已经由浏览器完成,但是直到最后我们才能确定。
-有限的工具-在SVG中,我们不再控制画布的每个像素,而是在向量基元的框架内进行思考和编码。 但是,对于这项任务而言,这是一个微不足道的负号,在竞争任务的背景下施加了一些又微不足道的限制。

我从来不必担心选择工具,因为我有一个令人恶心的角色特征-我是一个极简主义者,过去只在工作中使用我最喜欢的工具。 碰巧的是,从学生时代开始,当我在玩DirectDraw时,我最喜欢的工具始终是一张画布,上面可以“做你想做的事”。 解决竞争问题的画布确实很不错,但实际上它只发挥了我的一个优点:最广泛的优化机会,因为主要标准仍然是应用程序性能。

好的代码不好


任务很明确:您需要在正确的位置和正确的时间在画布上绘制点。 仍然需要编写代码。 同样,这一次有必要选择,在以程序样式编写带有一个“ footfoot”的高效紧凑代码之间,或者不是非常高效,甚至在我最喜欢的面向对象的紧凑环境中进行选择。 您可能已经猜到我选择了第二个选项,并用另一个我喜欢的类型-TypeScript对其进行了调味。

而且这种选择不是很正确。 由于使用了抽象和封装,因此并不总是能够保存,传输和重用中间计算结果,从而对性能产生不良影响。 而且由于这种方法的广泛使用,如果没有这种方法,JS中的OOP是不可能的,因此代码的精简性很差,而大小也很重要。

现在是时候提供指向github的链接了: github.com/native-elements/telechart 。 如果有兴趣,我建议您注意提交的历史记录;它会记录优化过程和每秒未能挤出两次额外渲染帧的失败尝试。

好吧,在比赛中我没有领奖。 而且这个问题,就像我们程序员经常遇到的那样,事实证明不是经验不足,机智或速度不足,而是自我批评不足:我设法做到这一点的事实并看起来像图片中的事实,我很高兴,但是至于渲染刹车,我以为我已经尽力了,其余的大概也一样。 我很to愧谈论这件事,但是我确信我会获得第一或第二名。 实际上,事实证明,我编写了一个刹车和越野车程序,不是最糟糕的,但远非最好的。 当我看到其他开发人员的工作时,我意识到我没有机会,只能咬肘。 如果我对自己的工作不偏不倚,我将从事生产力,这是竞争任务中最重要的部分。

我不厌倦的职业生涯中最有价值的教训之一是,与例如艺术家不同,一个好的工程师有义务客观地评估他的作品质量,放弃自信,因为他的作品的结果不仅应该取悦眼睛但应该可以正常运作。

这是比赛的第一阶段。 优胜者得到了丰厚的回报。 令我高兴的是,故事并没有就此结束,因为第二阶段已宣布:


有必要在短短一周内实施其他类型的图表来完善您的工艺。 我将立即显示发生了什么,下面将告诉您它是如何发生的。


就我而言,在添加新功能之前,我必须了解旧功能的性能。 我解决的第一个问题是

抽搐动画

即使您有足够的能力每秒产生60帧,如果元素的位置或其透明度不是由动画开始以来经过的时间决定的,则动画也不会平滑。 这是由于滴答之间的时间间隔不相等:例如,一个滴答在10毫秒后起作用,第二个滴答在40毫秒之后起作用,而对于第一个和第二个滴答,对象向左移动了1个像素-也就是说,其移动速度不断浮动,在视觉上看起来像是“抽搐”。 换句话说,您需要做一些错误的事情:

let left = 10, interval = setInterval(() => { left += 1 if (left >= 90) { clearInterval(interval) } }, 10) 

依此类推:

 let left = 10, startLeft = 10, targetLeft = 90, startTime = Date.now(), duration = 1000, interval = setInterval(() => { left = startLeft + (targetLeft - startLeft) * (Date.now() - startTime) / duration if (left >= targetLeft) { left = targetLeft clearInterval(interval) } }) 

由于代码中包含许多动画参数,因此我拍摄了一个通用类该类使任务更加容易,并且还增加了动画效果。 它很容易使用:

 let left = Telemation.create(10, 90, 1000) … drawVerticalLine(left.value) //      ,  . 

然后60 fps规则开始起作用。 PC游戏玩家会理解我:要使动画看起来完美,它必须以至少60 fps的速度渲染。 因此,帧的每个渲染应不超过1/60秒。 这需要强大的硬件和良好的代码。

进一步的研究表明

如果画布上方有html元素,则绘画画布的速度会降低

最初,我使用“空” html元素来实现对当前视口的控制:


这些元素放置在画布上,尽管它们没有内容,但仅用于跟踪鼠标事件,作为实验结果,事实证明它们的存在会降低渲染性能。 通过删除它们并使确定用于控制观看区域的事件的逻辑复杂化,我提高了渲染帧的速度。

仍然需要从演奏棺材的盖子上拉出最后一个钉子:我做到了

小地图缓存

在此之前,对于小地图,每帧都要绘制一条线。 这是一项昂贵的操作,因为它显示了整个年度的时间表(每行365点)。 我从一开始就懒于实现的显而易见的解决方案是为小型地图绘制一次图形线,将结果保存到缓存中,并在将来使用此缓存。 经过优化后,应用程序性能不再令人尴尬。

接下来呢?


仍然有许多成功而不是非常不理想的性能:尝试缓存坐标计算的结果,使用CanvasRenderingContext2D lineJoin参数进行实验(更快的斜接),但是它们并不那么有趣,因为它们没有显着提高性能或根本没有提高性能。

在这八天中,我花了五天时间来加速代码,而只花了三天时间来完成新功能。 是的,我只花了三天时间就添加了新类型的图表,在这里,OOP变得非常方便,代码库略有增加。 我没有足够的时间来完成奖励任务(另加5张图表)。 我相信我花了五天时间来消除自信心的后果,我可以花时间解决奖金问题。

尽管如此,我的工作还是取得了结果:第四名和一千美元的“安慰”奖:


顺便说一句,比赛继续进行,但是没有我。

我的参与使我感到高兴:除了有趣和有趣的冒险之外,我还获得了很好的专业经验和生活课程。

另外,我在开发公司时间跟踪器时使用了该库,我也计划在不久的将来讨论该库。

为了讨论,我提出以下问题:为什么电报需要所有这些? 我相信,只要有足够的钱,Telegram就会获得世界上最好的显示图表的图书馆:数百次尝试做得更好的最好结果。 竞争原则可以使您获得如此高的质量,以至于没人可以不花钱就下订单。

和一些链接:


Source: https://habr.com/ru/post/zh-CN460625/


All Articles