Serialization of JavaScript's chain-structured structure

Source: Internet
Author: User

First, Overview

In JavaScript, the chained pattern code, too much, is as follows:

If_else:

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

Switch

Switch (name) {case    ...: {//todo break        ;    }    Case ...: {//todo break        ;    }    default:{        //todo        }}

question: like these chained codes, what if we want to flatten them into chain-like processing? As follows:

FN1,F2,F3 is the processing function _if (FN1). _elseif (FN2). _else (FN3);

Here we come together to try to achieve the next chant.

Second, Chained code flattening

If, now 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! ');}

OK, now let's make it "flat" one step at a time.

In fact, look at the above code, it is not difficult to find that if...else this format, in fact, is the data structure of the single linked list, then the initial use of JavaScript to implement a single-linked list, 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,F3 is the judging function, and we assume that if, for example, F1, F2, and F3 return to ' next ', they continue to look down, otherwise, stop looking down. 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 pattern of the linked list.

However, our ultimate goal is to achieve the following?

FN1,F2,F3 is the processing function _if (FN1). _elseif (FN2). _else (FN3);

You may say, change the above code to the following so, not good?!!

Thens.push (F1). push (F2). push (F3). Resolve ();

but, JavaScript's Push method returns the new length of the array, not the array object.

So , we can only write a new Add method, the effect and push, but return the array object. 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, we are the Add, resolve method binding in the global variable thens, can not always create an array each time you copy and paste the method, so the refactoring 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, add,resolve this public method, in each instantiation, are created again is unscientific, so, using prototype on the original basis of the continued deformation, as follows:

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++) {                I F (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 then, we have to manually new a slink every time, a bit of a hassle, so we'll wrap the new slink into a function, like jquery, as follows:

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 ();

OK, done, next is the problem of grammatical sugar drop, the collation 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 using arrays this way, you can also use closures to achieve the chain flattening effect, as follows:

var func = Function.prototype;func._else = Func._elseif = Function (fn) {    var _this = this;    return function () {        var res = _this.apply (this,arguments);        if (res=== "next") {  //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 ');
Third, asynchronous code chain-flattening

What we're talking about here is the synchronization process, what if there is an asynchronous case in a chained call function?

What do you 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 will F1 use settimeout to become asynchronous, according to the above code logic, should be waiting for F1 complete execution (including settimeout execution), determine whether to execute F2, but really so?

The test code is as follows:

_if (F1). _elseif (F2). _else (F3). Resolve ();

The result of executing the code is that nothing is output.

Why?

Because JavaScript is a single thread. See (here) for details

So how do we fix it?

Because of the asynchronous code, and the subsequent chain must be processed after the asynchronous code, we wait for the asynchronous code to execute after the subsequent chain is executed, as follows:

function F1 (name) {    setTimeout (function () {        if (name = = = ' Monkey ') {            console.log (' Yes, I am Monkey ');        } else{            //processing follow-up chain            this.resolve (name, 1),//1 represents the next function to be processed in the array position        }    }.bind (this), 2000);}

Well, because in the function, we used this, which represents the Slink object, and changed the Resolve method, solid, need to fine-tune Slink constructor and prototype chain, as follows:

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)!== ' n Ext ') {break                    ;                }            }            return this;                }}

The test code is as follows:

function F1 (name) {    setTimeout (function () {        if (name = = = ' Monkey ') {            console.log (' Yes, I am Monkey ');        } else{            //processing follow-up chain            this.resolve (name, 1),//1 represents the next function to be processed in the array position        }    }.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, the purpose is the same, to achieve the purpose of the asynchronous code flattening, but the code here is much simpler than the promise. See (here) for promise details.

Serialization of JavaScript's chain-structured structure

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.