Detailed description of JavaScript chain structure serialization

Source: Internet
Author: User
I. Overview In JavaScript, there are too many chained code, as shown in the following code: if_else: if (...) {TODO} elseif (...) {TODO} else {TODO} switch: switch (name) {case...: {TODObreak;} case...: {TODO .. i. Overview

In JavaScript, there are too many chained code, as shown below:

If_else:

if(...){    //TODO}else if(...){    //TODO}else{    //TODO}

Switch:

switch(name){    case ...:{        //TODO        break;    }    case ...:{        //TODO        break;    }    default:{        //TODO        }}

Question:For example, what if we want to flat the chain code above? As follows:

// Fn1, f2, f3 is the processing function _ if (fn1). _ elseIf (fn2). _ else (fn3 );

Next we will try to implement it together.

Ii. Flat chain code

Assume that we have the following chained code:

if(name === 'Monkey'){    console.log('yes, I am Monkey');}else if(name === 'Dorie'){    console.log('yes, I am Dorie');}else{    console.log('sorry, over for ending!');}

Now, we will "flat" it step by step ".

In fact, looking at the code above, it is not difficult to find that if... Else is actually a single-chain table in the data structure. Therefore, JavaScript is used to implement a single-chain table as follows:

var thens = [];thens.resolve = function(name){    for(var i = 0, len = this.length; i < len;i++){        if(this[i](name) !== 'next'){            break;        }    }}thens.push(f1, f2, f3);

Where f1, f2, and f3 are judgment functions, and we assume that if f1, f2, and f3 return 'Next', continue searching. Otherwise, stop searching. As follows:

function f1(name){    if(name === 'Monkey'){        console.log('yes, I am Monkey');    }else{        return 'next';    }}function f2(name){    if(name === 'Dorie'){        console.log('yes, I am Dorie');    }else{        return 'next';    }}function f3(){    console.log('sorry, over for ending!');}

Well, this is the linked list mode.

However,What is our ultimate goal?

// Fn1, f2, f3 is the processing function _ if (fn1). _ elseIf (fn2). _ else (fn3 );

You may say that it is okay to change the above Code to the following code ?!!

thens.push(f1).push(f2).push(f3).resolve();

But,The push method in JavaScript returns the new length of the array instead of the array object.

So,Then we can only write a new add method. The effect is the same as push, but the array object is returned. As follows:

thens.add = function(f){    if(typeof f === 'function'){        this.push(f);        return this;            }        }

The test code is as follows:

var thens = [];thens.add = function(f){    if(typeof f === 'function'){        this.push(f);        return this;            }        }thens.resolve = function(name){    for(var i = 0, len = this.length; i < len;i++){        if(this[i](name) !== 'next'){            break;        }    }    }thens.add(f1).add(f2).add(f3).resolve();

However, there is a drawback in this way: we bind the add and resolve methods to the global variable thens. We cannot copy and paste the methods every time we create an array, the reconstruction code is as follows:

function Slink(){    this.thens = [];    this.thens.add = function(f){        if(typeof f === 'function'){            this.push(f);            return this;                }            }    this.thens.resolve = function(name){        for(var i = 0, len = this.length; i < len;i++){            if(this[i](name) !== 'next'){                break;            }        }        }}

Obviously, it is unscientific to create a public method such as add and resolve during each instantiation. so, prototype is used to continue deformation on the original basis, as shown below:

function Slink(){    this.thens = [];}Slink.prototype = {    add: function(f){            if(typeof f === 'function'){                this.thens.push(f);                return this;                    }            },    resolve: function(name){            for(var i = 0, len = this.thens.length; i < len; i++){                if(this.thens[i](name) !== 'next'){                    break;                }            }        }}

The test code is as follows:

var thens = new Slink();thens.add(f1).add(f2).add(f3);thens.resolve();

Yes, but in this case, we have to manually create a new Slink every time, which is a little troublesome. Therefore, we encapsulate the new Slink process into functions, just like jQuery, as shown below:

function $go(f){    return new Slink(f);}function Slink(f){    this.thens = [];    this.thens.push(f);}Slink.prototype = {    add: function(f){            if(typeof f === 'function'){                this.thens.push(f);                return this;                    }            },    resolve: function(name){            for(var i = 0, len = this.thens.length; i < len; i++){                if(this.thens[i](name) !== 'next'){                    break;                }            }        }}

The test code is as follows:

$go(f1).add(f2).add(f3).resolve();

Okay, I'm done. The next step is the syntax sugar drop problem. The Code is as follows:

function _if(f){    return new Slink(f);}function Slink(f){    this.thens = [];    this.thens.push(f);}Slink.prototype = {    _elseIf: function(f){            if(typeof f === 'function'){                this.thens.push(f);                return this;                    }            },    _else: function(f){            return this._elseIf(f);    },    resolve: function(name){            for(var i = 0, len = this.thens.length; i < len; i++){                if(this.thens[i](name) !== 'next'){                    break;                }            }            return this;                }}

The test code is as follows:

_if(f1)._elseIf(f2)._else(f3).resolve();

Of course, in addition to the array method, you can also use the closure to achieve the flat effect of the chain, as shown below:

Var func = Function. prototype; func. _ else = func. _ elseIf = function (fn) {var _ this = this; return function () {var res = _ this. apply (this, arguments); if (res = "next") {// The value is Boolean return fn. apply (this, arguments);} return res ;}}

The test code is as follows:

function f1(name){    if(name === 'Monkey'){        console.log('yes, I am Monkey');    }else{        return 'next';    }}function f2(name){    if(name === 'Dorie'){        console.log('yes, I am Dorie');    }else{        return 'next';    }}function f3(){    console.log('sorry, over for ending!');}f1._elseIf(f2)._else(f3)('Dorie');
Iii. flattening asynchronous code chains

We have discussed the synchronization process above. What if the chain call function is asynchronous?

What does it mean? As follows:

function f1(name){    setTimeout(function(){        if(name === 'Monkey'){            console.log('yes, I am Monkey');        }else{            return 'next';        }    }, 2000);}function f2(name){    if(name === 'Dorie'){        console.log('yes, I am Dorie');    }else{        return 'next';    }}function f3(){    console.log('sorry, over for ending!');}

We converted f1 from setTimeout to asynchronous. According to the logic of the above Code, we should determine whether to execute f2 after f1 is fully executed (including setTimeout execution). But is it true?

The test code is as follows:

_if(f1)._elseIf(f2)._else(f3).resolve();

The result of code execution is that nothing is output.

Why?

Because JavaScript is a single thread. For more information, see (here)

How can this problem be solved?

Because there is asynchronous code that must be processed after the asynchronous code, we will wait until the asynchronous code is executed to execute the subsequent chain, as shown below:

Function f1 (name) {setTimeout (function () {if (name = 'monkey') {console. log ('Yes, I am monkey');} else {// process the subsequent chain this. resolve (name, 1); // 1 represents the position of the next handler in the array }}. bind (this), 2000 );}

Well, because this is used in the function, it represents the Slink object, and changed the resolve method, fixed, and needs to slightly adjust the Slink constructor and prototype chain, as shown below:

function Slink(f){    this.thens = [];    this.thens.push(f.bind(this));}Slink.prototype = {    _elseIf: function(f){            if(typeof f === 'function'){                this.thens.push(f.bind(this));                return this;                    }            },    _else: function(f){            return this._elseIf(f.bind(this));    },    resolve: function(name, flag){            for(var i = flag, len = this.thens.length; i < len; i++){                if(this.thens[i](name) !== 'next'){                    break;                }            }            return this;                }}

The test code is as follows:

Function f1 (name) {setTimeout (function () {if (name = 'monkey') {console. log ('Yes, I am monkey');} else {// process the subsequent chain this. resolve (name, 1); // 1 represents the position of the next handler in the array }}. bind (this), 2000);} function f2 (name) {if (name = 'dorie') {console. log ('Yes, I am Dorie ');} else {return 'Next';} function f3 () {console. log ('Sorry, over for ending! ');} _ If (f1). _ elseIf (f2). _ else (f3). resolve ('', 0 );

Haha, If you know Promise, do you feel so similar.

Yes, they all share the same purpose to flatten asynchronous code, but the code here is much simpler than Promise. For more information about Promise, see (here ).

The above is the detailed description of JavaScript chain structure serialization. For more information, see the PHP Chinese Network (www.php1.cn )!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.