Github’s address welcomes star

preface

There are several ways to bind events in the React DOM:

  1. Bind in Constructor.

  2. Or use the arrow function (no this).

  3. For the form that requires dynamic parameter transmission:

    • You can use closures

    • Or you can pass a handler directly to a child component, which takes its arguments and then executes the parent component’s handler

    class App extends Component {
    removeCharacter = index => () => {
        const {list} = this.state;
        list.splice(index, 1);
        this.setState({
            list
        })
    }

    render() {
        return( <div> { this.state.list.map((value, Index) =>(<div onClick={this.removecharacter (index)} key={value.id} data={value} > click me </div>))} </div>)}} // Class OtherApp extends Component {removeCharacter = index => {const {list} = this.state; list.splice(index, 1); this.setState({ list }) }render() {
        return (
            <div>
                {
                    this.state.list.map((value, index) =>(
                        <Child 
                            onClick={this.removeCharacter}
                            index={index}
                            key={value.id}
                            data={value}
                        />
                    ))
                }
            </div>
        )
    }
}

class Child extends Component {
    handleClick = () => {
        const { index, onClick} = this.props;
        onClick(index)
    }
    render() {
        return (
            <div onClick={this.handleClick}>
                {this.props.data}
            </div>
        )
    }
}
Copy the code

The performance comparison depends on the specific environment (and browser, platform optimization are related), nothing is absolutely good performance.

Seeing the conclusion of this blog post, I want to make a practical comparison:

If JSX goes in render every timebindThis method is going to consume performance because every timebindAlways return a new function, and it's definitely not appropriate to create static functions repeatedly (so are closures, butbindThere are a bunch of algorithms inside, much more complicated than closures.)Copy the code

Compare the performance of bind and closure arguments in React

Chrome Version 72.0.3626.119 (Official Build) (64-bit)

The react version “16.8.3”

The node version v10.15.1

Performance analysis using Chrome’S JavaScript Profiler shows that the render time for 1000 events is about the same (both using the first refresh).

  1. First, bind:

  2. In the form of closures:

  3. Adopt the mode without parameters:

Can see the performance was similar in both sides, and on the Stack Overflow stackoverflow.com/questions/1… Bind is much slower than closure when testing the performance of chrome’s various versions of Bind and Closure and proxy (click).

Function.prototype.bind = function (context) {

    if(typeof this ! = ="function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);

    var fNOP = function () {};

    var fBound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
    }

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
    return fBound;
}
Copy the code

Discover that the internal implementation is also a closure! Bind is better than closure in terms of readability, so bind is slower than closure, but V8 has been optimized so that react doesn’t make much of a difference.

The realization of the v8 inside (from stackoverflow.com/questions/1…). , have not checked the latest implementation.

function FunctionBind(this_arg) { // Length is 1.
  if(! IS_SPEC_FUNCTION(this)) { throw new$TypeError('Bind must be called on a function');
  }
  var boundFunction = function () {
    // Poison .arguments and .caller, but is otherwise not detectable.
    "use strict";
    // This function must not use any object literals (Object, Array, RegExp),
    // since the literals-array is being used to store the bound data.
    if (%_IsConstructCall()) {
      return %NewObjectFromBound(boundFunction);
    }
    var bindings = %BoundFunctionGetBindings(boundFunction);

    var argc = %_ArgumentsLength();
    if (argc == 0) {
      return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
    }
    if (bindings.length === 2) {
      return %Apply(bindings[0], bindings[1], arguments, 0, argc);
    }
    var bound_argc = bindings.length - 2;
    var argv = new InternalArray(bound_argc + argc);
    for (var i = 0; i < bound_argc; i++) {
      argv[i] = bindings[i + 2];
    }
    for (var j = 0; j < argc; j++) {
      argv[i++] = %_Arguments(j);
    }
    return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
  };

  %FunctionRemovePrototype(boundFunction);
  var new_length = 0;
  if (%_ClassOf(this) == "Function") {
    // Function or FunctionProxy.
    var old_length = this.length;
    // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
    if ((typeof old_length === "number") &&
        ((old_length >>> 0) === old_length)) {
      var argc = %_ArgumentsLength();
      if (argc > 0) argc--;  // Don't count the thisArg as parameter. new_length = old_length - argc; if (new_length < 0) new_length = 0; } } // This runtime function finds any remaining arguments on the stack, // so we don't pass the arguments object.
  var result = %FunctionBindArguments(boundFunction, this,
                                      this_arg, new_length);

  // We already have caller and arguments properties on functions, / /which are non-configurable. It therefore makes no sence to
  // try to redefine these as defined by the spec. The spec says
  // that bind should make these throw a TypeError if get or set
  // is called and make them non-enumerable and non-configurable.
  // To be consistent with our normal functions we leave this as it is.
  // TODO(lrn): Do set these to be thrower.
  return result;
Copy the code

We see some extra overhead in the bind implementation methods, such as ‘%_IsConstructCall()’, to implement the bind specification, which makes bind slower than a simple closure in most cases. Bind, on the other hand, is slightly different. Functions created using function.prototype. bind have no prototype attributes or internal attributes of [[Code]], [[FormalParameters]], and [[Scope]].

In summary, when bind and closure are not performance bottlenecks, prioritize readability and keep your code as simple as possible

If there is any mistake or not precise place, please be sure to give correction, thank you very much!

reference

  1. Wulv. Site / 2017-07-02 /…
  2. Stackoverflow.com/questions/1…
  3. Github.com/mqyqingfeng…
  4. Developers.google.com/web/tools/c…