GithubHelp home page GithubHelp logo

kikobeats / js-mythbusters Goto Github PK

View Code? Open in Web Editor NEW
631.0 20.0 67.0 1.65 MB

:ghost: STHAP js, where is my perf?

Home Page: https://mythbusters.js.org

License: MIT License

JavaScript 12.91% SCSS 87.09%
perfomance myth javascript handbook

js-mythbusters's Introduction


JS MythBusters

A JavaScript optimization handbook from a high level point of view.


js-mythbusters's People

Contributors

davissorenson avatar dependabot-preview[bot] avatar edysegura avatar elrumordelaluz avatar gangsthub avatar greenkeeper[bot] avatar hanford avatar hntrdglss avatar hristozov avatar iamrohitanshu avatar jeroenvisser101 avatar jsdelivrbot avatar juliannicholls avatar kerwitz avatar kikobeats avatar kilometres avatar leon-paul-hart avatar lioness100 avatar luisadame avatar martinmuzatko avatar miparnisari avatar mk-pmb avatar ms314006 avatar philterz avatar rossolson avatar rstacruz avatar sage7will avatar supercoffee avatar tombyrer avatar umamialex avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-mythbusters's Issues

Number example is incorrect

You have the following example in parsing of numbers:

const toNumber = num => ~~num
console.log(toNumber('10.9'))
// => 10.9

But according to your table, the output should be 10

Therefore, this should be:

const toNumber = num => ~~num
console.log(toNumber('10.9'))
// => 10

A mention to performance optimization

Hey me again,

I would suggest a short paragraph to make the user aware of eager optimizations and the fact it is often an enemy.

Measure it, don't guess it

Add WeakMaps section

Reading about Proxies at
https://hacks.mozilla.org/2015/07/es6-in-depth-proxies-and-reflect/

I found a very nice WeakMaps usage example:

Proxies β™₯ WeakMaps. In our readOnlyView example, we create a new proxy every time an object is accessed. It could save a lot of memory to cache every proxy we create in a WeakMap, so that however many times an object is passed to readOnlyView, only a single proxy is created for it.

  throw new Error("can't modify read-only view");
}

var handler = {
  // Override all five mutating methods.
  set: NOPE,
  defineProperty: NOPE,
  deleteProperty: NOPE,
  preventExtensions: NOPE,
  setPrototypeOf: NOPE
};

function readOnlyView(target) {
  return new Proxy(target, handler);
}

This is one of the motivating use cases for WeakMap.

Because WeakMaps is confused with Maps, could be interesting add a section about when to use WeakMaps

write about ASM.js

I didn't remember the article, but I started understanding why wasm when I understood browsers spend a lot of time in parsing step.

Need to investigate a bit.

Define local variables

When a variable is referenced, Javascript hunts it down by looping through the different members of the scope chain. This scope chain is the set of variables available within the current scope, and across all major browsers it has at least two items: a set of local variables and a set of global variables.
Simply put, the deeper the engine has to dig into this scope chain, the longer the operation will take. It first goes through the local variables starting with this, the function arguments, then any locally defined variables, and afterwards iterates through any global variables.

Regular Expression Flags

Unicode Flag (u)

The unicode flag was recently added:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode

It should be used by default!

/^.$/.test('a') //βœ…
/^.$/.test('🐢') //❌
/^.$/u.test('🐢') //βœ…

dot all flag (s)

By default, . matches any character except for line terminators:

/foo.bar/u.test('foo\nbar');
// β†’ false
(It doesn’t match astral Unicode symbols either, but we fixed that by enabling the u flag.)

ES2018 introduces dotAll mode, enabled through the s flag. In dotAll mode, . matches line terminators as well.

/foo.bar/su.test('foo\nbar');
// β†’ true

__

both flags can be used as the new standard

Reference:

Symbol API explained

Context:
It would be great if we can explain how the new ES6 Symbol API works and how toPromitive is used in every type coercion.

Screenshots:
screen shot 2018-03-22 at 18 37 22
screen shot 2018-03-22 at 18 37 33
screen shot 2018-03-22 at 18 37 42

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on all branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because we are using your CI build statuses to figure out when to notify you about breaking changes.

Since we did not receive a CI status on the greenkeeper/initial branch, we assume that you still need to configure it.

If you have already set up a CI for this repository, you might need to check your configuration. Make sure it will run on all new branches. If you don’t want it to run on every branch, you can whitelist branches starting with greenkeeper/.

We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

Once you have installed CI on this repository, you’ll need to re-trigger Greenkeeper’s initial Pull Request. To do this, please delete the greenkeeper/initial branch in this repository, and then remove and re-add this repository to the Greenkeeper integration’s white list on Github. You'll find this list on your repo or organiszation’s settings page, under Installed GitHub Apps.

Node single event loop and multi-threading.

Context

Node is single threaded. That is a very simple explanation of how it works. There is a thread pool to manage file handles. Two event loops, the main one and the worker pool. The main loop is divided in several important phases so it would be great to explain them in a simple way and how threading is managed in node/v8.

References

Needs more context

Without context or explanation of the fundamentals, these "mythbusting" statements are of low value. See #25

You need to take in account

  • V8 optimizers' impact based on different scenarios
  • Hardware profile
  • Browser/Node JS version

A very blatant example is in https://mythbusters.js.org/#/v8-tips/freeing-memory
Consider a scenario were your object is not used as a class-type element with an explicit structure, but rather like a dictionary were keys are added and removed dynamically. Setting keys to null will release the reference to the element, but the dictionary will still hold a pointer for that key, slowing down lookups significantly.

With a clear example, you could illustrate the impact of both approaches.

An example for hardware profile would be the over usage of V8 C++ - side methods, which perform exponentially better on bigger hardware. You can witness this in libraries that implement protocols in pure-js versus their C++ bindings version.

A lot of bundled JS methods also take advantage of this, like JSON.stringify/ JSON.parse.
You can try benchmarking https://github.com/compactr/compactr.js on different machines to see just how big of a difference it makes.

For Node version, Buffers got a speed boost recently in Node 8. Prior to that, it was much faster to use arrays/ UINT8Arrays. In the browser, Buffers are polyfilled as UINT8Arrays anyways.

PDF version

Have you thought about a PDF version?

The PDF will be all the .md in in the same order that are in the website.

JS code caching

Improved code caching

V8 uses code caching to cache the generated code for frequently-used scripts. Starting with Chrome 66, we are caching more code by generating the cache after top-level execution. This leads to a 20-40% reduction in parse and compilation time during the initial load.

Please note that:

  • V8 uses two kinds of code caching to cache generated code to be reused later.
  • The first is the in-memory cache that is available within each instance of V8.
  • The other kind of code caching serializes the generated code and stores it on disk for future use.

https://v8project.blogspot.com.es/2018/04/improved-code-caching.html

Passing arguments by reference vs value

Javascript is always pass by value, but when a variable refers to an object (including arrays), the "value" is a reference to the object.
Changing the value of a variable never changes the underlying primitive or object, it just points the variable to a new primitive or object.
However, changing a property of an object referenced by a variable does change the underlying object.

  • Explain what is Pure Functions and why you should use this approach.

setImmediate vs setTimeout vs process.nextTick

   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”Œβ”€>β”‚        timers         β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  β”‚     I/O callbacks     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  β”‚     idle, prepare     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚   incoming:   β”‚
β”‚  β”‚         poll          β”‚<──────  connections, β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚   data, etc.  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚  β”‚        check          β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
└───    close callbacks    β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Use setImmediate if you want to queue the function behind whatever I/O event callbacks that are already in the event queue.

  • Use process.nextTick to effectively queue the function at the head of the event queue so that it executes immediately after the current function completes. It's slightly faster than setTimeout:

'use strict'

var bench = require('fastbench')

var run = bench([
  function benchSetImmediate (done) {
    setImmediate(done)
  },
  function benchNextTick (done) {
    process.nextTick(done)
  }
], 1024 * 1024)

// run them two times
run(run)

Considerations on browser side

  • on browser side, setImmediate/process.nextTick is not available.
  • A simple solution is setTimeout(fn, 0).

Refactor Variable access

Hey, very nice initiative and website πŸ‘

The items.length part in Variable access is not always true and even probably wrong for your example. Most modern VMs apply loop-invariant code motion. Array#length is no exception, there is a very detailed article that explains what happens here: http://mrale.ph/blog/2014/12/24/array-length-caching.html.

I'd suggest refactoring this part and mentioning that accessing Array#length IS OK (myth busted) if the loop body does not mutate the array or is simple enough.

function is faster for detecting whether a string matches a regex pattern.

Another interesting benchmark is String.prototype.indexOf vs RegExp.prototype.test, I personally expected the latter to be faster, that’s what happens in Firefox, but in Chrome, it’s not. RegExp.prototype.test is 32% faster on Firefox, while String.prototype.indexOf is 33% faster on Chrome. In times like this, go with the one you like most, i think.

https://jsperf.com/exec-vs-match-vs-test-vs-search/5
https://jsperf.com/search-vs-indexof11/4
https://jsperf.com/regexp-indexof-perf
https://jsperf.com/regexp-test-search-vs-indexof/12

Object properties and array items are slower than variables

When it comes to Javascript data, there’s pretty much four ways to access it: literal values, variables, object properties, and array items. When thinking about optimization, literal values and variables perform about the same, and are significantly faster than object properties and array items.
So whenever you reference an object property or array item multiple times, you can get a performance boost by defining a variable. (This applies to both reading and writing data.)
While this rule holds mostly true, Firefox has done some interesting things to optimize array indexes, and actually performs better with array items than with variables. But the performance drawbacks of array items in other browsers mean that you should still avoid array lookups, unless you are really only targeting Firefox performance.

jsPerf alternative?

I really do love jsPerf (even wrote a tutorial for jsPerf for a Meetup). But it needs Java... which is kinda something I try to avoid.

Thanks for your resource; I'll have to add in my finds later.

This isn't really mythbusting, just spreading myths?

I like the idea, but two pieces of feedback:

  1. The colour scheme is dark and is okay, in general. However code samples look terrible, particularly comments on them which end up being a dark text on dark background situation.

  2. The main point: None of these appear to be actual mythbusting, at least that I've seen so far. No benchmarks or other repeatable bits of code. Just "Hey this is better!", which amounts to little more than myths in and of itself. Mythbusters was all about taking myths, creating an experiment and figuring out if it was true or not. e.g. http://mythbusters.js.org/workflow/math.html at the very least there should be some simple microbenchmarks there.

Add how to clone section

This is a popular internet topic.

About:

  1. How to clone an array
const newArray = arr.slice(0)
const anotherArray = [...arr]
  1. How to clone a plain object
const newObj = Object.assign({}, obj)
const anotherObj = {...obj}

also known as shallow clone:

> third = {hello: 'world'}
> obj = {foo: 'bar', third}
{ foo: 'bar', third: { hello: 'world' } }
> shallow = Object.assign({}, obj)
{ foo: 'bar', third: { hello: 'world' } }
> shallow
{ foo: 'bar', third: { hello: 'world' } }
> third
{ hello: 'world' }
> third.hello = 'test'
'test'
> shallow
{ foo: 'bar', third: { hello: 'test' } }
  1. How to clone a deep object and why a simple clone is not enough (talk about passing by value and reference).
const deepClone = obj => {
  let clone = Object.assign({}, obj);
  Object.keys(clone).forEach(
    key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
  );
  return clone;
};
  1. Why JSON.parse(JSON.stringify(value)) is not enough.
  • Will throw error in circular objects.
  • The JSON.stringify conversion has to be lossless. Therefore, methods are not allowed as members of type function are ignored by the JSON stringifier. The undefined value is not allowed either. Object keys with undefined value are omitted, while undefined values in arrays are substituted by null.
  • Members of the Date object become ISO-8601 strings, not representing the timezone of the client. The value new Date(2011,0,1) becomes "2010-12-31T23:00:00.000Z" after executing the above deep copy method in case you live in Central Europe.
  1. Why not possible do it async style.

parse/stringify is a CPU intensive task, so no I/O is here and not supported from low level Node.js API.
The only "async" way possible is in deepClone wrap each deepClone call into a process.nextTick, simulating deferrer it.

Inspiration:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.