Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bind variables to callback function

I'm calling some database functions from my request handlers. All of these functions do separate "error callbacks" for handling errors. Example:

function referralComplete(req, res) {     /*getting id etc.*/     db.startDatabaseConnection(function() {         db.flagReferralAsDone(id, function(success) {             db.endDatabaseConnection();             /*doing stuff on success*/         }, onError);     }, onError);      function onError(err, description) {         logger.error(description + ": " + err);         user.pageNotFound(req, res);     } } 

I have several request handlers similar to this all calling different database functions. At the moment I have duplicated onError() into the scope of each of them since I need req and res when handling the error, but I like think that there might be a way to achieve the same without the duplication.

So the question is, would it be possible to somehow bind req and res to onError() so that I won't have to duplicate onError() into each request handler?

like image 991
rongved Avatar asked Jul 17 '13 22:07

rongved


People also ask

How do you bind a callback function?

Explicitly set this of the callback - part 1bind [docs], which returns a new function with this bound to a value. The function has exactly the same behavior as the one you called . bind on, only that this was set by you. No matter how or when that function is called, this will always refer to the passed value.

Can callback functions have parameters?

Yes. The print( ) function takes another function as a parameter and calls it inside. This is valid in JavaScript and we call it a “callback”. So a function that is passed to another function as a parameter is a callback function.

How do you pass parameters in callback function in react?

Passing the event object of react as the second argument. If you want to pass a parameter to the click event handler you need to make use of the arrow function or bind the function. If you pass the argument directly the onClick function would be called automatically even before pressing the button.


1 Answers

Binding is simple!

db.startDatabaseConnection(function(){   // whatever }, onError.bind(this, var1, var2)); 

You can learn more about binding by clicking this awesome link, even though the link is sort of long.

Here's a real basic demo

// a function var something = function (a, b, c) {   console.log(a, b, c); };  // a binding of something with 3 defined args var b = something.bind(null, 1, 2, 3);  // call b b(); //=> 1 2 3 

Behind the scenes, this is basically what's happening

// ES6 const myBind = (f, context, ...x) =>   (...y) => f.call(context, ...x, ...y);  // ES5 var myBind = function(fn, context) {   var x = Array.prototype.slice.call(arguments, 2);   return function() {     var y = Array.prototype.slice.call(arguments, 0);      return fn.apply(context, x.concat(y));   }; };  var b = myBind(console.log, console, 1, 2, 3);  b(); // => 1 2 3  b(4,5,6) // => 1 2 3 4 5 6  

Context?

Context allows you to dynamically change the this of your function. Note you can only bind the context of functions defined with the function keyword; arrow functions have a lexical this that cannot be manipulated. This is shown for sake of completeness, but I do advise against this kind of program. It's usually better to just use another function parameter instead of relying on dynamic function context, this. Supporting context switching like this is to enable object-oriented style in JavaScript. Unless you are using this style, I see no reason to pay attention to context.

const getCanvas = (id) =>    document.getElementById(id).getContext('2d')    const draw = function (canvas, x = 0, y = 0)  { canvas.beginPath()    canvas.strokeStyle = this.color             // `this` refers to context!    canvas.rect(x, y, this.width, this.height)  // `this` refers to context!    canvas.stroke()  }    // create two contexts  const contextA =    { color: 'blue', width: 10, height: 10 }      const contextB =    { color: 'green', width: 10, height: 20 }    // bind the draw function to each context and the canvas  const drawA =    draw.bind(contextA, getCanvas('main'))      const drawB =    draw.bind(contextB, getCanvas('main'))    // call the bound drawing functions normally  // draw three blue squares  drawA(0, 0)  drawA(20, 0)  drawA(40, 0)    // and one green rect  drawB(80, 0)
<canvas id="main"></canvas>

Partial application

Similar to binding is Partial Application

In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.

Here we could make a very simple partial helper procedure which helps us accomplish this

const identity = x =>    x    const partial = (f = identity, ...x) =>    (...y) => f (...x, ...y)    const foo = (...all) =>    console.log ('array of', all)    partial (foo, 1, 2, 3) (4, 5, 6)  // 'array of', [ 1, 2, 3, 4, 5, 6 ]

Currying

Currying is related to, but not the same as, binding or partial application

In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument.

const identity = x =>    x    const curry = (f = identity, arity = f.length) => x =>  {    const next = (xs = []) =>      xs.length >= arity        ? f (...xs)        : x => next ([ ...xs, x ])    return next ([ x ])  }    const foo = (a, b, c) =>    console.log ('a', a, 'b', b, 'c', c)    curry (foo) (1) (2) (3)  // 'a' 1 'b' 2 'c' 3    curry (foo) ('choo') ('bye') ()  // 'a' 'choo' 'b' 'bye' 'c' undefined
like image 89
Mulan Avatar answered Oct 05 '22 23:10

Mulan