This article will not introduce Async code yet, but sequential programming, which is actually a good segue to promises and async code.
for us a sequential program is as easy as it sounds, a program with components that execute in sequence based on a previous component in the sequence(chain)
e.g String operations in JS
"Hello World".split("").reverse().join("")
// split reverse and join will execute in sequence based on the
// previous component's(object) result
This sequence or chain formed by these functions is formally known as method chaining.
Method Chaining(MC)
a simple, even not complete explanation of MC to build from would be: passing down an object from method to method in a chain
let's think about objects a bit
Dot operations and Objects
Dot Op examples
.forEach()
.toString()
.call()
.bind()
A dot operation accesses a property of an object.
const simpleObject = {
name: "sk"
}
console.log(simpleObject.name) // sk - produce by a simple dot op
Dot op's assumption in JS is fairly simple: Dot op assumes whatever is being operated on is an object(whether during runtime or declaration), the right side of the dot assumes the left is an object
let str = new String("hello")
let arr = new Array()
console.log(typeof str) // Object
console.log(typeof arr) // Object
str.split()
arr.forEach()
// fun fact most primitives in JS are turned to objects during
// runtime, hence it's possible to dot operate on a primitive
// e.g string "Hello world".split()
what's the point of all this?
yAxisG
.append("text")
.attr('class', 'axis-label')
.attr('y', -80)
.attr('x', -innerHeight / 2)
.attr('transform', `rotate(-90)`)
.attr('fill', 'black')
.attr('text-anchor', 'middle')
.text(YaxisLabel)
what you looking at is a snippet of D3, a JS visualization library, chaining multiple dot operations, we said the right side of dot ops assume the left is an object.
let's look at append from D3
append("text").attr("class", "axis-label")
// attr assumes append is an object, not only an object, but one
// that has a property attr, which is a function
// this is what attr assumes
const append = {
attr: function(arg1, arg2){
// do some attr stuff
}
}
append('text').attr()
// however if you observe carefully append is not an object,
// but a function("text") taking a text arg ,
// so how is this possible, simple
// append returns an object with the method attr
// and that is what method chaining is: passing down an object //from method to method in the chain
// will make sense as we implement it
append returns an object with the attr method, attr returns an object with the attr and text method and so on,
but we do not have to define the shape of the passed objects by "hand", we have OOP for that, we know that the this
keyword refers to the context around it, if called inside an object this
refers to that object, we can achieve method chaining by having a bunch of methods in an object, each function after doing it's job, returns this
, which refers to the current object
const chainable = {
one : function() {
console.log("one")
return this; // this === chainable object
},
two: function () {
console.log("two")
return this
},
three: function() {
console.log("three")
return this;
}
}
chainable.one()
.one()
.one()
.two()
.three()
.one()
// you can create a huge sequence as you can see above, each
//method will return chainable
// to take it a step further you can even encode state in chainable and have it updated as you go along
// it's very easy
each method in chainable returns well: the chainable object, each dot operation in the chain expects the previous one to return an object, which defines the accessed property for example
chainable
.one() // expects chainable to have method one
.two() // expects one() to have method two(), which does not but returns an object that does
// and so on
you can achieve this with classes also.
class Axis{
append(text){
// do something with text
console.log(text)
return this; // current instance object
}
attr(key, property){
// do something
console.log(key, property)
return this
}
text(text){
// do something
console.log(text)
return this
}
}
const yAxis = new Axis()
yAxis
.append("hello world")
.attr("zIndex", 1)
.attr("backgroundColor", "black")
.text("hello again")
.text("good bye")
.attr("display", "flex")
With that we achieve sequential programming, doing an operation based on the previous one, this is a good Segue to promises, as this is what promises are (kind of), methods that return objects called promises, these objects define then, catch and finally methods(sound familiar?)
next we will introduce promises