My plugin allows you to specify a callback in its options. The plugin may run before the DOM is ready, but I need to make sure the callback only runs once the DOM is ready, so I'm wrapping the callback.call() within a $( document ).ready() handler.
The problem is I want to maintain the plugin's context within the callback. In other words, within the callback, I want this to be the plugin, not document.
This is what I've come up with, but I'm not sure it's really the best way.
function MyPlugin( element, options ){
this.element = element;
this.options = $.extend( {}, defaults, options );
MyPlugin.prototype = {
functionWithCallback: function(){
if ( typeof this.options.callback == 'function' )
$( document ).ready( function( plugin ){ plugin.options.callback.call( plugin ) }( this )
}
}
}
That last line is ugly, but it allows me to pass the plugin's this context to the callback.
I would rather do $( document ).ready( this.options.callback ) and be done with it, but then within the callback, this is document which doesn't really help, and doesn't necessarily give me easy access to the element the plugin was called on...
Is there a better way?
Function.prototype.call is a perfectly solid solution for this sort of situation.
Calling functions with a different context of this is part of what it's for.
If you'd like a more elegant but ES5 solution (so newer browsers only) you can use .bind
$(document).ready(plugin.options.callback.bind(plugin));
Bind sets a function's this value for when you call it (as well as other parameters optionally). Here's an example of how .bind works.
jQuery shims it with $.proxy if you'd like to use that.
You can also do
$(plugin.options.callback.bind(plugin));
Related
I'm finding a little confusing sometimes you need to bind the context to a function call and sometimes not. When exactly can you avoid it and when you not?
What's the difference between those lines?
<a #click="${this.handler.bind(this)}">link</a>
<a #click="${this.handler()}">link</a>
<a #click="${this.handler}">link</a>
<a #click="${()=>this.handler()}">link</a>
Also sometimes in the constructor() you need
this.handler = this.handler.bind(this)
to make the function call works, sometimes you not. What's the differences between all those cases?
In the first 4 lines I am guessing you usually wrap them in between ${ and }.
With this mention these 3 lines:
<a #click="${this.handler.bind(this)}">link</a>
<a #click="${this.handler}">link</a>
<a #click="${()=>this.handler()}">link</a>
would be pretty similar in the effect. When you attach an event handler you need to pass a reference to a function/method to call, while the second line:
<a #click="${this.handler()}">link</a>
will most likely just be wrong. That's because you will be calling this.handler() as soon as the rendering is done. The only way it might make some sense it would be if the handler method returns a function.
Going back to the first 3 lines: they will indeed have very similar effect, as in all of them you are passing references to a local method render, but:
the first one doesn't need binding as the method will anyway be
called in this context (but I guess it doesn't hurt either)
the third one adds the definition of an anonymous function as an
event handler, which when called it will invoke this.handler
So the second one is basically the simplest and easiest to read.
When it comes to the need to call bind in some of the cases: that's needed when your method is called from another context. Let's say you pass it as a callback parameter to a method running in another class. When you method will be called there, it will have by default the context of that other object. So you will need to use .bind(this) to make sure that when the method is called in your element's context.
Your method does work, but it's running from another this. So maybe that's why some of the times you don't notice the need to .bind(this). If the method just shows a message, calls some other external service, or anything else that is not part of your object's definition (that doesn't use this.something), it will work without using bind.
UPDATE: in fact I think an event handler will always run in the context of the element that originated that event. I am guessing that lit just does that .bind(this) when we use that #click= syntax, as it would make a lot of sense.
Note that binding directly in templates is generally not a good idea. It can result in performance issues and components re-rendering when they shouldn't.
https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/no-template-bind.md
As to why you sometimes need to bind consider this:
#customElement('main-page')
export class MainPage extends LitElement {
#property()
public name = "bob";
render() {
return html`<button #click=${this.clicked}>Click Me!</button>`;
}
clicked() {
console.log("clicked " + this.name);
console.log("this in clicked: " + this)
setTimeout(this.sayHi, 1000);
}
sayHi() {
console.log("this in sayHi: " + this)
alert(`Hello, ${this.name}!`);
}
}
If we click on the button, we get the name logged properly:
But the name isn't shown in the alert:
If we look at this in both functions we get different results:
One is an HTMLElement and the other one is a Window. What this refers to is different once we pass sayHi to setTimeout.
Bind will fix this by making sure that this refers to the right object.
While we could do setTimeout(this.sayHi.bind(this), 1000); and it would fix our issue but it's not very clean and it's error prone. We could bind it in the constructor, but this also isn't much better.
The cleanest way to do it is to directly bind this by using an arrow function instead:
sayHi = () => {
[...]
This notation binds this to the object itself. We then do not need to bind it explicitly ourselves.
Once we do that, both this refer to the right object:
There are several 'After' hooks and one of them should be first than others, how it could be configured in the Cucumber JS?
You can explicitly configure hooks to run in a certain order:
#Before(order = 10) // Annotated method
public void doSomething(){
// Do something before each scenario
}
Before(10, () -> { // Lambda
// Do something before each scenario
});
It seems this also works for #After hooks.
Edit: Leaving this in case it's useful for any Java people - missed that it was JS, sorry! But for Javascript:
Hooks are executed in the order in which they're defined. If that doesn't do it for you, create one hook and explicitly call the other methods.
Ordered by top to bottom in the hooks file
After({}, async function() {
return "This will run first";
});
After({}, async function() {
return "tThis will run second";
});
You can use tags concept for each scenario in cucumber feature file and use same tag on each #After annotation which will resolve for which test scenario's that specific #After should execute
Hooks is a file which will be executed from top to bottom. If you have more After tags, go in such a way that which you want to close first of all will be first and the last what you want to execute to be last. If you have tags in your feature file, pass that information to the specific After
Node programmers conventionally use a paradigm like this:
let callback = function(err, data) {
if (err) { /* do something if there was an error */ }
/* other logic here */
};
Why not simplify the function to accept only a single parameter, which is either an error, or the response?
let callback = function(data) {
if (isError(data)) { /* do something if there was an error */ }
/* other logic here */
};
Seems simpler. The only downside I can see is that functions can't return errors as their actual intended return value - but I believe that is an incredibly insignificant use-case.
Why is the error-first pattern considered standard?
EDIT: Implementation of isError:
let isError = obj => obj instanceof Error;
ANOTHER EDIT: Is it possible that my alternate method is somewhat more convenient than node convention, because callbacks which only accept one parameter are more likely to be reusable for non-callback use-cases as well?
(See "Update" below for an npm module to use the callback convention from the question.)
This is just a convention. Node could use the convention that you suggest as well - with the exception that you wouldn't be able to return an error object as an intended value on success as you noticed, which may or may not be a problem, depending on your particular requirements.
The thing with the current Node convention is that sometimes the callbacks may not expect any data and the err is the only parameter that they take, and sometimes the functions expect more than one value on success - for example see
request(url, (err, res, data) => {
if (err) {
// you have error
} else {
// you have both res and data
}
});
See this answer for a full example of the above code.
But you might as well make the first parameter to be an error even in functions that take more than one parameter, I don't see any issue with your style even then.
The error-first Node-style callbacks is what was originally used by Ryan Dahl and it is now pretty universal and expected for any asynchronous functions that take callbacks. Not that this convention is better than what you suggest or worse, but having a convention - whatever it is - make the composition of callbacks and callback taking functions possible, and modules like async rely on that.
In fact, I see one way in which your idea is superior to the classical Node convention - it's impossible to call the callback with both error and the first non-error argument defined, which is possible for Node style callbacks and sometimes can happen. Both conventions could potentially have the callback called twice though - which is a problem.
But there is another widely used convention in JavaScript in general and Node in particular, where it's impossible to define both error and data and additionally it's impossible to call the callback twice - instead of taking a callback you return a promise and instead of explicitly checking the error value in if as is the case in Node-style callbacks or your style callbacks, you can separately add success and failure callbacks that only get relevant data.
All of those styles are pretty much equivalent in what they can do:
nodeStyle(params, function (err, data) {
if (err) {
// error
} else {
// success
}
};
yourStyle(params, function (data) {
if (isError(data)) {
// error
} else {
// success
}
};
promiseStyle(params)
.then(function (data) {
// success
})
.catch(function (err) {
// error
});
Promises may be more convenient for your needs and those are already widely supported with a lot of tools to use them, like Bluebird and others.
You can see some other answers where I explain the difference between callbacks and promises and how to use the together in more detail, which may be helpful to you in this case:
A detailed explanation on how to use callbacks and promises
Explanation on how to use promises in complex request handlers
An explanation of what a promise really is, on the example of AJAX requests
Examples of mixing callbacks with promises
Of course I see no reason why you couldn't write a module that converts Node-style callbacks into your style callbacks or vice versa, and the same with promises, much like promisify and asCallback work in Bluebird. It certainly seems doable if working with your callback style is more convenient for you.
Update
I just published a module on npm that you can use to have your preferred style of callbacks:
https://www.npmjs.com/package/errc
You can install it and use in your project with:
npm install errc --save
It allows you to have a code like this:
var errc = require('errc');
var fs = require('fs');
var isError = function(obj) {
try { return obj instanceof Error; } catch(e) {}
return false;
};
var callback = function(data) {
if (isError(data)) {
console.log('Error:', data.message);
} else {
console.log('Success:', data);
}
};
fs.readFile('example.txt', errc(callback));
For more examples see:
https://github.com/rsp/node-errc-example
I wrote this module as an example of how to manipulate functions and callbacks to suit your needs, but I released it under the MIT license and published on npm so you can use it in real projects if you want.
This demonstrates the flexibility of Node, its callback model and the possibility to write higher-order functions to create your own APIs that suit your needs. I publish it in hope that it may be useful as an example to understand the Node callback style.
Because without this convention, developers would have to maintain different signatures and APIs, without knowing where to place the error in the arguments array.
In most cases, there can be many arguments, but only one error - and you know where to find it.
Joyent even wrote about this at the time they were more involved:
Callbacks are the most basic way of delivering an event
asynchronously. The user passes you a function (the callback), and you
invoke it sometime later when the asynchronous operation completes.
The usual pattern is that the callback is invoked as callback(err,
result), where only one of err and result is non-null, depending on
whether the operation succeeded or failed.
Yeah we can develop code style as you said. But there would be some problems.If we maintain code style what we want , different signatures of API increases and of course there would be dilemma between developers. They create their layers( error and success stages for example) again. Common conventions play an important role in spreading best practices among developers.
Ingenral, the error-first Node-style callbacks is what was originally used by Ryan Dahl and it is now pretty universal and expected for any asynchronous functions that take callbacks. Not that this convention is better than what you suggest or worse, but having a convention - whatever it is - make the composition of callbacks and callback taking functions possible, and modules like async rely on that.
I would like to store a variable that is shared between all stack frames (top down) in a call chain. Much like ThreadLocal in Java or C#.
I have found https://github.com/othiym23/node-continuation-local-storage but it keeps loosing context for all my use cases and it seems that you have to patch the libraries you are using to make it local-storage-aware which is more or less impossible for our code base.
Are there really not any other options available in Node? Could domains, stacktraces or something like that be used to get a handle (id) to the current call chain. If this is possible I can write my own thread-local implementation.
Yes, it is possible. Thomas Watson has spoken about it at NodeConf Oslo 2016 in his Instrumenting Node.js in Production (alt.link).
It uses Node.js tracing - AsyncWrap (which should eventually become a well-established part of the public Node API). You can see an example in the open-source Opbeat Node agent or, perhaps even better, check out the talk slides and example code.
Now that more than a year has passed since I originally asked this question, it finally looks like we have a working solution in the form of Async Hooks in Node.js 8.
https://nodejs.org/api/async_hooks.html
The API is still experimental, but even then it looks like there is already a fork of Continuation-Local-Storage that uses this new API internally.
https://www.npmjs.com/package/cls-hooked
TLS is used in some places where ordinary, single-threaded programs would use global variables but where this would be inappropriate in multithreaded cases.
Since javascript does not have exposed threads, global variable is the simplest answer to your question, but using one is a bad practice.
You should instead use a closure: just wrap all your asynchronous calls into a function and define your variable there.
Functions and callbacks created within closure
(function() (
var visibleToAll=0;
functionWithCallback( params, function(err,result) {
visibleToAll++;
// ...
anotherFunctionWithCallback( params, function(err,result) {
visibleToAll++
// ...
});
});
functionReturningPromise(params).then(function(result) {
visibleToAll++;
// ...
}).then(function(result) {
visibleToAll++;
// ...
});
))();
Functions created outside of closure
Should you require your variable to be visible inside functions not defined within request scope, you can create a context object instead and pass it to functions:
(function c() (
var ctx = { visibleToAll: 0 };
functionWithCallback( params, ctx, function(err,result) {
ctx.visibleToAll++;
// ...
anotherFunctionWithCallback( params, ctx, function(err,result) {
ctx.visibleToAll++
// ...
});
});
functionReturningPromise(params,ctx).then(function(result) {
ctx.visibleToAll++;
// ...
}).then(function(result) {
ctx.visibleToAll++;
// ...
});
))();
Using approach above all of your functions called inside c() get reference to same ctx object, but different calls to c() have their own contexts. In typical use case, c() would be your request handler.
Binding context to this
You could bind your context object to this in called functions by invoking them via Function.prototype.call:
functionWithCallback.call(ctx, ...)
...creating new function instance with Function.prototype.bind:
var boundFunctionWithCallback = functionWithCallback.bind(ctx)
...or using promise utility function like bluebird's .bind
Promise.bind(ctx, functionReturningPromise(data) ).then( ... )
Any of these would make ctx available inside your function as this:
this.visibleToAll ++;
...however it has no real advantage over passing context around - your function still has to be aware of context passed via this, and you could accidentally pollute global object should you ever call function without context.
Typically, in "constructor" you subscribe to events with lambda-functions:
function Something(){
this.on('message', function(){ ... });
}
util.inherits(Something, events.EventEmitter);
This works well but extends bad. Methods play better with inheritance:
function Something(){
this.on('message', this._onMessage);
}
util.inherits(Something, events.EventEmitter);
Something.prototype._onMessage = function(){ ... };
What are the best practices to keep these event handler functions?
if i understood the question correctly then i think that it depends on how much open for changes you are willing to be.
your second example opens the option for subclasses (or, actually, any class) to override the handler's code, which isn't necessarily a good thing.
the first example prevents overriding but at the cost of having anonymous functions (sometimes containing a lot of code) inside your constructor. however, this code can be extracted to another private function (not on the prototype, just a regular function inside the module's file).
the open-close principal deals with this kind of questions.