ES6 Modules, stop execution of code - javascript

It sounds like an odd question: How can I leave the execution context from an ES6 module?
See the following example:
Module1 requires some features in the browser to be present (say some new stuff not every Browser implements currentl).
You want to do a check in the module, if the required feature is available and if not, you want to stop the execution.
When writing that with an immediate function call, you can just call return and the following code is never executed.
How to do that in an ES6 module? Do I have to wrap the whole code into an if block?

If you export executable code from an ES6 module, you usually do so as a function:
export function myFunction() {
...
}
---
import { myFunction } from './module';
myFunction();
This function works just like any other that you define directly in the calling module. You can simply return to the caller as you would otherwise:
export function myFunction() {
if(...) return;
...
}

There's no special tools (that I'm aware of) in ES6/ES2015 to do this. Furthermore, all exports must be top-level. This also means that if a module ever has a given export, it will always have that export. The value of that export can change, of course, but the export "interface" must always be the same.
If you don't want to export certain values if a condition isn't met then you won't be able to do that. However, you can always make those values null or undefined in that case. If exporting isn't a problem, there are a few tools from ES5 and before that you can use.
The IIFE (as you know):
(function() {
...
if (someCondition) {
return;
}
// code that won't run
})();
A single iteration for loop (no idea why you'd use this but you could):
for (var i = 0; i < 1; i++) {
...
if (someCondition) {
break;
}
// code that won't run
}
And a good old-fashioned if statement:
...
if (!someCondition) {
// code that won't run
}

Related

Any tips on context manager similar to Python in Javascript?

I quite liked Python's context manager where I did not have to be concerned with how the resource was obtained or cleaned up afterwards. Is there a way to do this in a neat way in Javascript?
You can make something similar using generator functions in javascript:
function* usingGroup() {
// setup
console.group()
try {
yield
} finally {
// cleanup
console.groupEnd()
}
}
and to use it, you can use a for ... of loop:
for(const _ of usingGroup()) {
console.log('inside a group')
}
This method is similar to how you define context managers in python using the #contextmanager decorator. Although the way of using a for loop to define where the context applies feels strange in my opinion.
How does it work:
Abstracting away the whole generator object and iterator protocol, you can think of it as doing this: before the first iteration of the loop, the code inside the generator function is run until the yield statement, at this point, the for loop body runs once since a value has been yielded by the generator, before the next iteration, the rest of the code in the generator is run. Since it does not yield, the loop considers it done and exits without executing its body again. The try ... finally ensures that even if an error is thrown, the code gets executed.
If you need to use some value inside your loop (like a file you opened for example), you can just yield it inside the generator.
full code:
function* usingGroup() {
console.group()
try {
yield
} finally {
console.groupEnd()
}
}
for(const _ of usingGroup()) {
console.log('inside a group')
}
I'm happy to break this to you, we now have that in JavaScript. It's a tiny library called "contextlib" (closely resembling python's contexlib).
Disclaimer: I authored contextlib.
You can install using npm install contextlib.
import {With, contextmanager} from 'contextlib';
class context:
enter() { console.log('entering context') }
exit() { console.log('leaving context') }
With(new context(), () => {
console.log('inside context')
})
You can also use the contextmanager decorator
context = contextmanager(function*(){
try {
console.log('entering context')
yield
} finally {
console.log('leaving context')
}
})
You should check it out on github.
I also surprised by missing this feature. Unfortunately, only callback based solutions are available in JS
https://promise-nuggets.github.io/articles/21-context-managers-transactions.html

Javascript ES6 reuse exports with callback

Let's say I have 2 JavaScript files like the followings and they both import from fileimport.js(reusability)
The goal is, the fileimport.js has an event listener runs on each page. I want to call custom functions for each of the pages after the event runs.
file1.js
import * as fileimport from './fileimport';
...
callback(){
//run custom function
}
file2.js
import * as fileimport from './fileimport';
...
callback(){
//run custom function
}
fileimport.js
...
export ReusableFunc1(){
....
}
export ReusableFunc2(){
....
}
export Func3{
form.addEventListener('submit', function (e) { callback })// I want to call callback() for each of the pages that import this.
}
I tried adding the callback() inside the fileimport.js and override in the regular pages but it did not work out(it did not call the regular pages function). How can I achieve something like this.
If you have a file A.js which provides code, that is used in B.js and C.js, than this file loaded and parsed only once. So a function call within A.js will be triggered only once, when the file is loaded.
If you want to call a function, provided by A.js whenever code from A.js is included somewhere, you cannot use an event listener, since there isn't any.
One thing you always can do is to trigger the desired function »manually« whenever you import A.js.
//A.js
const fx1 = () => {}
const fx2 = () => {}
const callback = () => {}
export { callback }
export default { fx1, fx1 }
//B.js
import { * as CodeFromA, callback } from 'A.js';
callback();
Another thing could be to change the export of A.js to something like:
export default () => {
callback();
return { ReusableFunc1, ReusableFunc2 }
}
This way you can:
import CodeFromA from 'A.js'
const ReusableFx = CodeFromA();
That would ensure that you get error if you try to use any of those ReusableFunc* without triggering the callback before.
The problem is callback is not defined in fileimport.js. You would need circular dependency in order to achieve that, but I suggest you treat them with care, since, quoting this relevant article which I suggest you read:
They are not always evil, but you might want to treat them with special care. They cause tight coupling of the mutually dependent modules. These kinds of modules are harder to understand and reuse as doing so might cause a ripple effect where a local change to one module has global effects.
If you don't need to call the callback function at import time, you shouldn't give you many problems though.
That being said, this would be the code to achieve what you want with a function:
file1.js
import * as fileimport from './fileimport';
...
export function callback() {
//run custom function
}
fileimport.js
import * as file1 from './file1';
ReusableFunc1(){
....
}
eventListener() {
file1.callback();
}
As you can see, the problem remains if you have a lot of callback functions. If the number of functions you need to call increases, I suggest you change your code architecture not to have so much dependency from other modules.

Mocking a global object when unit testing function with jasmine

I need to write tests for legacy JavaScript script which runs from node.js. It has a global object which is initialised in one function and then accessed from another. I mean script.js looks like:
var object;
function first() {
object = Initialise.object();
...
}
function second() {
object.doSomething();
...
}
I need to write a unit test for the second() function. We are using a jasmine test framework and I am struggling to create a mock (stub) for the object. It is because I don't know how can I access it from script-spec.js. I have tried
var script = require("../src/script.js");
var testObject = script.object;
but testObject is undefined.
My knowledge of JavaScript is limited which doesn't help me as well (I have Java background).
How can I test second() function? I understand that I might need to refactor/redesign script.js which I am OK with.
I would rewrite the code to be more functional:
function first() {
return Initialise.object();
}
function second(object) {
object.doSomething();
...
}
Then later when the code is used:
var object = first()
second(object)
Then mocking becomes pretty trivial, because you can control what gets passed as an argument to second in the test.
Check out Avoid Side Effects in the Clean Code Javascript repo for some more info about this.
It would be easier if it was a global variable, you could just do a global.object = mockObject. What it really is a module level variable, modules are really just functions. The only way to reassign object is from a function defined inside script.js such as
function injectMockObject (mockObject) {
object = mockObject;
}
which you would need to add to script.js

How to call/use this module in other JS files/modules

I read some JS module design patterns recently. I came across this small code snippet as below.
(function(window) {
var Module = {
data: "I'm happy now!"
};
window.Module = Module;
})(window);
Still not quite understand this code well, my questions are:
How to use/call this module outside this particluar JS file? Need I
assign a variable to this module? e.g. var module1 = (...)(...);
Could anyone explain what the window parameter here stands for?
Is it a good practice to have two/three such kind of modules in the
same file?
The main reason to create an anonymous function in this case is to prevent global object pollution. It's not really a module pattern.
The problem arise when you declare a variable. Without the function scope, the variable will be added to the global object (window). If you were to declare the variables within a function. It would add the variable to the function scope without polluting the global object window.
What happen is that a javascript file could add a variable named foo and on a different file use that variable named foo too. Unless you really want to have a variable shared by two javascript files, it would probably create conflicts and bug that are difficult to fix.
For example: a.js
var foo = "one"
b.js
var foo = "two"
c.js
alert(foo)
In this case, the alert box might show either "one" or "two", depending of the order in the javascript files are included.
But having this a.js:
(function () {
var foo = "one"
})()
b.js
(function () {
var foo = "two"
})()
c.js
(function () {
alert(foo)
})()
This would create an error as you cannot alert a non declared variable.
One way to detect undefined variables, is to make sure to execute the javascript code in strict mode.
To do that, add the string "use strict" at the top of the file or function.
function () {
"use strict"
...
}
Undeclared variable will raise errors and it should be possible to fix the code that way.
Also, if you forget to declare a variable with the var keyword, it might end up adding the variable to the global scope even if the code is scoped into a function. The only way to prevent global scope pollution is to run the code in strict mode.
In the code snippet that you provided, the module with name Module is explicitly added to the window object. You can access the window object from any place in javascript unless the window name is ghosted by an other variable.
Now, back to the modules. If you want to define modules, it can be done in many ways. As an exemple, you could create an object on the window object called modules. In this object, you'll insert your modules.
module.js
window.modules = {}
foo.js
(function (window) {
var module = {}
...
window.modules.foo = module
})(window)
This variant isn't super good as you have to manually add the module to the modules object. You have to manually modify the window object, and that can be subject to errors.
modules.js
window.modules = {}
function define(name, constructor) {
var module = {exports: {}}
constructor(module)
window.modules[name] = module.exports
}
function require(name) {
return window.modules[name]
}
foo.js
define("foo", function (module) {
module.exports.one = function () {
return 1
}
module.exports.plus = function (a, b) {
return a + b
}
})
bar.js
define("bar", function (module) {
module.exports = function () {
var foo = require("foo")
return foo.plus(foo.one(), foo.one())
}
})
This is a module definition that looks a bit like module defined with http://requirejs.org/. It is quite basic as it doesn't take into account module dependencies so if bar is loaded and used before foo. Then the require method won't be able to return the module.
Also, if you want to store modules without having them visible into the global scope, you can only define the require and define method on the window object and hide modules into an anonymous scope like this:
(function (window) {
var modules = {}
function define(name, constructor) {
var module = {exports: {}}
constructor(module)
modules[name] = module.exports
}
function require(name) {
return modules[name]
}
window.define = define
window.require = require
})(window)
This way, define and require are the only function that can give you access to modules. Other modules won't be able to modify other modules without requiring them first. This can be useful when using third parties script that could conflict with your module system.
In fact this is not a module, but a Self-Invoking Ananymous function or an Immediate function which gets an object in parameter and assign a Module property to it:
The page window is a parameter passed to this function.
So an object named Module containing a data property is assigned to window.
JavaScript Self-Invoking Functions:
A self-invoking expression is invoked (started) automatically, without being called.
Function expressions will execute automatically if the expression is
followed by ().
You cannot self-invoke a function declaration.
You have to add parentheses around the function to indicate that it is
a function expression
So As you can see Immediate Functions can't be called as its name states it will be immediately executed and by its self, no other function or scope can execute it.
For better reference take a look at :
Javascript Self Invoking Functions.
Self-Invoking Functions section in JavaScript Function Definitions.
And concerning your last question about its benefits and good practices as shown on the given Article reference:
Where to use self-executing functions?
One obvious situation is when you want to auto-run a function like I
showed in above example but that is trivial. If you are in a situation
where you want to run a piece of code repeatedly like updating
something in the database based on user interaction or fetching
records from database every 10 seconds or you want to load new stories
via ajax similar to how facebook does on its homepage or some other
similar situation, one would normally go for setInterval function
something like this:
setInterval(doStuff, 10000);
Above, doStuff function will get called every 10 seconds. That is the
normal approach most developers seem to go with. However, there is a
huge problem with that.
The setInterval will call doStuff function exactly at specified time of 10 seconds again and again irrespective
of whether doStuff function actually finished doing what it is
supposed to do. That is bad and will certainly get you into unexpected
results.
That is one example of where setInterval is "bad" and should be
avoided.
This is exactly where self-executing functions come in handy. We can
do the same task with the help of self-executing function along with
setTimeout like this:
function foo(){
// your other code here
setTimeout(foo, 10000);
}();
This code will also repeat itself again and again with one difference.
setTimeout will never get triggered unless doStuff is finished. A much
better approach than using setInterval in this situation.
Calling it from another file:
And if this function is on another file it will be called automatically if this file is included.
Why do we use Self-Invoking Functions in JavaScript?
And if you ask yourself why do we use these functions, self-invoked function are used to manage Variable Scope.
Take a look at the answer here for further information.

How do I test 'normal' (non-Node specific) JavaScript functions with Mocha?

This seems like it should be extremely simple; however, after two hours of reading and trial-and-error without success, I'm admitting defeat and asking you guys!
I'm trying to use Mocha with Should.js to test some JavaScript functions, but I'm running into scoping issues. I've simplified it down to the most basic of test cases, but I cannot get it working.
I have a file named functions.js, which just contains the following:
function testFunction() {
return 1;
}
And my tests.js (located in the same folder) contents:
require('./functions.js')
describe('tests', function(){
describe('testFunction', function(){
it('should return 1', function(){
testFunction().should.equal(1);
})
})
})
This test fails with a ReferenceError: testFunction is not defined.
I can see why, because most of the examples I've found either attach objects and functions to the Node global object or export them using module.exports—but using either of these approaches means my function code would throw errors in a standard browser situation, where those objects don't exist.
So how can I access standalone functions which are declared in a separate script file from my tests, without using Node-specific syntax?
Thanks to the other answers here, I've got things working.
One thing which wasn't mentioned though—perhaps because it's common knowledge among Noders—was that you need to assign the result of the require call to a variable, so that you can refer to it when calling your exported functions from within the test suite.
Here's my complete code, for future reference:
functions.js:
function testFunction () {
return 1;
}
// If we're running under Node
if (typeof exports !== 'undefined') {
exports.testFunction = testFunction;
}
tests.js:
var myCode = require('./functions')
describe('tests', function(){
describe('testFunction', function(){
it('should return 1', function(){
// Call the exported function from the module
myCode.testFunction().should.equal(1);
})
})
})
require('./functions.js')
That doesn't do anything since you're not exporting anything. What you're expecting is that testFunction is globally available, essentially the same as
global.testFunction = function() {
return 1;
}
You just can't bypass the export/globals mechanism. It's the way node has been designed. There is no implicit global shared context (like window on a browser). Every "global" variable in a module is trapped in it's context.
You should use module.exports. If you intend to share that file with a browser environments, there are ways to make it compatible. For a quick hack just do window.module = {}; jQuery.extend(window, module.exports) in the browser, or if (typeof exports !== 'undefined'){ exports.testFunction = testFunction } for node.
If you want to make any module available through require you should use
module.exports
as you know ;)
there is a solution if you want to use a module in Node and in browser by doing this
function testFunction() { /* code */ }
if (typeof exports !== 'undefined') {
exports.testFunction = testFunction
}
by doing this you will be able to use the file in browser and in node environment

Categories