Here's an english transcript of my talk on RND.JS
On the slide: "Inserting like Google"
Today I'm going to talk about the embeds. It is when the page contains parts included from the third-party website.
On the slide: Weather forecast informer
You've seen the embeds before. It can be something useful...
On the slide: "Have you notice a cat rubs you? There's a reason! Curious facts"
...or nasty ads...
On the slide: "The scientists proved: The Earth consists of two planets..."
...or ads...
On the slide: "Cheap iPhone replica! / You're the winner!"
...More ads!
On the slide: Rambler Top 100 counter
Or something that makes no difference for the user, but is useful for the website admin.
Every vendor tells their code is easy to embed. A 5 y.o. child can do that and everything would be just fine.
On the slide: "Embeds" -> "Troubles". A reference to a Soviet cartoon.
But it's not always just fine. Sometimes the embeds are troubles. Let's see what bad can happen.
Polluting the global scope.
An actual code that AddThis service runs on a page. It's questionable, should the embed polyfill something or not. But if it is, it should at least do it right. AddThis code doesn't check if the browser already have .bind method.
Polluting the markup.
This is a code from GetSatifaction. If you press the button to the left, the popup appears. The popup can be called programmatically, without the button. But the button... You got it, it cannot be hidden.
Well. It can be hidden. But this selector is obscure. And we even accidentally removed it once.
Slow loading.
Here's a typical embed code, a script tag inserted into head that loads the library. And that lib is used somewhere later on the page.
This script is synchronous (blocking). And it's HTTPS. Because security and stuff.
But SSL handshake is 5-way. Imagine he have a 40 ms ping. Including domain name resolve it turns out that after 120 ms we even didn't send the request headers yet. And rest of the page waits this process to end.
- And what if we place this script tag just before the closing body tag?
Good point. But DOMContentLoaded event is still delayed. And sometimes DOMContentLoaded is not the end of loading, but only the beginning.
Slow runtime.
Setting Flash banners aside, there's something that may slow down the page. For example, Qbaka, a JS error reporter. In order to intercept errors it had to pacth the setTimeout, requestAnimation, etc.
As a result, 5..7% of perfomance improvement after the code was removed.
So. We don't want embeds to stall the page and to pollute it. the same as we want from any script.
On the slide: "Telemetry".
Let's talk about real world examples. About something that monitors the page and sends info to the server. I'll call this a telemetry.
Yandex-metrika.
Here's how their code looked like few years ago. Blocking HTTPS script. Just as I've mentioned above.
But eventually smart Yandex guys noticed that and decided to use async scripts.
But the problem with async script is that you cannot tell when exactly it has been loaded. So we should use $.load (an example from the official docs!) to track an event. Becuase if the page was loaded entirely, the async code was loaded for sure.
Okay. What Google guys did instead.
Again, this code was used few years ago. They insert an async script as well.
And in order to track an event you just call a push method of a global object named underscore-gaq passing an array with first value set to underscore-track-event.
What the?
But hey! It's actually convenient! Before the async code is loaded, by _gaq.push we just add new item to the array.
Then the script loads, grabs the contents of that array and pushes it to the server.
At the same time, window._gaq becomes an object with method "push"...
...that sends the data immediately.
On the slide: "First, code is used, and then it is loaded."
So we use same invocation before the script loads and after that.
And it's worth mentioning modern GA API offers ga() instead of _gaq.push(). It looks better, but it's essentially the same under the hood.
On the slide: "Widgets".
Let's talk about that is visible to the user. I mean, widgets of all kinds.
On the slide: "Dynamically generated images"
The oldest way to embed stuff...
On the slide: I own my for ... years / I'm pregnant for ... days.
...still alive. Pros: It's bullet-proof; virtually any browser from any dumpster can display images. Cons: It's not interactive. And the server load for generating the image is higher that fro generating text. You can generate images that are text, though: SVG.
Iframes. Just point its src to the specific URL and voila!
Here's an example. They can be interactive. But only within their sandboxes, not interacting with the host page. It's good for the payment forms, but bad for anything else. You cannot even dynamically resize the iframe element. So if you're providing the width and height attributes in an embed code example, it's forever.
Can't we instead generate the markup using JS? We can. The docwrite is the easiest way. But the docwrite is evil.
Not that kind of evil.
It's this kind of evil: like, c'mon, dude, just use dowrite, try it! It breaks all the abstractions. It works only in sync scripts. Until few years ago browsers even didn't start to download resources later in the document, because docwriting <plaintext> tag would mess up anything.
Usually, docwrite is used by ads makers. But here's what I've found on vk.com! It's a pure legacy: windows-1251, comments inside script tag, and docwrite of course.
You may not believe me, but I have a notarized screenshot! (Reference to a russian meme.)
Moving on. A div with certain id telling where the script should render.
Here's an example, again, vk.com. We at TradingView have the same embedding method.
And guess what. Not all our users are happy. And this happens mostly because they forget to actually create a div with the required id. And if they need two widgets on a page, things are getting worse.
Partially this problem can be solved by using classes.
Like on this Twitter embed code. thoses classes are hardcoded and connot be overriden by the user.
Also, notice that the like will work even with disabled JavaScript.
But: we still cannot insert those buttons asynchronously. If the link is not in the document at the time script works, it would not be converted to a button.
There's something that also identifies the script related stuff: the src attribute. I saw this technique on Google Plus button.
The embed code looks like this. Plain and simple. The script just replaces its own element with button.
And it can be inserted asynchronously as well.
On the slide: "In depth"
Let's get a closer look.
On the slide: "How to find yourself"
How the script should find itself? Bad news: It's hard to get the exact element in the document that represents the currently running script.
Good news: We don't need that.
All we have to do is to get all the scripts...
...filter out only those with matching sources...
...and replace it. In one pass. If there's several matching scripts in the document, first pass will replace all entries. The other calls would just do nothing.
On the slide: "Configuration"
It's nice when there's a simple unconfigurable button. But what if we have to use settings?
We can use GET params. Bad idea. The browser cache would not work well.
Hash params? It's good for iframes, but for the script we have something better.
Data attributes. Once we have a reference to a script element, we can read its attributes.
Or - the magic. If the script has src attribute, its content is not executed. But it still can be read! So we can place a JSON here.
Or YAML.
Or anything at all.
For example, LaTeX formulas. Those could just be replaced with images.
On the slide: "Show me the code!"
And I actually made the demo that does exacly so. For this meetup.
On the slide: "Conclusion"
Time to wrap up. In conclusion let's just recall that if you're going to write an embed code...
...do not be a slowpoke, do not shit up the place...
...do not make your users feel like an idiot.
Make them feel happy!
Thank you!
We're hiring.









































































