Saturday, April 14, 2018

JavaScript lazy-loading

function counterEager(): Iterable<number> {
    console.log('counterEager: ');

    const list = [];
    for (let i = 1; i <= 5; i++) {        
        list.push(i);
        console.log('pushed value ' + i);
    }

    console.log('counterEager ends');

    return list;
}


function* counterLazy(): Iterable<number> {
    console.log('\ncounterLazy: ');

    for (let i = 1; i <= 5; i++) {                        
        yield i;
        console.log(`resuming value ${i}`);
    }        
}


function* counterLazyMultiple(): Iterable<number> {            
    console.log('\ncounterLazyMultiple: ');
        
    const a = [100, 200, 300];            
    yield* a;
    console.log('resuming value 300');    
    yield 400;
    console.log('resuming value 400');    
    yield* a;
    console.log('resuming value 300');    
}



function* counterLazyWithMixedReturnType() {        
    console.log('\ncounterLazyWithMixedReturnType: ');

    const a = [100, 200, 300];
    yield* a;
    console.log('resuming value 300');
    yield 400;
    console.log('resuming value 400');
    yield a;
    console.log('resuming value 100, 200, 300');    
}

for (const i of counterEager()) {
    console.log('value: ' + i);    
}

let n = 1;
for (const i of counterLazy()) {
    console.log(`received value #${n++}: ${i}`);  
}

n = 1;
for (const i of counterLazyMultiple()) {
    console.log(`received value #${n++}: ${i}`);      
}

n = 1;
for (const i of counterLazyWithMixedReturnType()) {
    console.log(`received value #${n++}: ${i}`);      
}


Output:
Developers-iMac:it dev$ ts-node sample.ts 
ounterEager: 
pushed value 1
pushed value 2
pushed value 3
pushed value 4
pushed value 5
counterEager ends
value: 1
value: 2
value: 3
value: 4
value: 5

counterLazy: 
received value #1: 1
resuming value 1
received value #2: 2
resuming value 2
received value #3: 3
resuming value 3
received value #4: 4
resuming value 4
received value #5: 5
resuming value 5

counterLazyMultiple: 
received value #1: 100
received value #2: 200
received value #3: 300
resuming value 300
received value #4: 400
resuming value 400
received value #5: 100
received value #6: 200
received value #7: 300
resuming value 300

counterLazyWithMixedReturnType: 
received value #1: 100
received value #2: 200
received value #3: 300
resuming value 300
received value #4: 400
resuming value 400
received value #5: 100,200,300
resuming value 100, 200, 300


Unless you really want to yield the array itself instead of the array's individual elements, it's a good practice to explicitly indicate the return type when using TypeScript, the compiler can help you spot accidental error of yielding the array itself instead of yielding the array's individual elements:



On following, without the explicit type, the array itself (number[]) is yielded instead of its individual elements (number). Miss a single character (asterisk), the code will do different. See the output above.




It's interesting that JavaScript can yield individual elements from a list without looping by just suffixing the yield keyword with asterisk.

yield* listHere;

C# still don't have that functionality.

https://stackoverflow.com/questions/6957659/yield-multiple-ienumerables

https://stackoverflow.com/questions/5415902/c-yield-return-range-collection


And also, JavaScript syntax for generator is terser than C#. Javascript's yield elementHere vs C#'s yield return elementHere


Have C# used yield elementHere instead of yield return elementHere, yielding individual elements from an array without looping could have this syntax for C#:

yield foreach listHere;


C# team might be having a second thought to introduce syntactic sugar like this:
yield return foreach listHere;


Further reading:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function%2A

https://blog.johncrisostomo.com/basic-generators-in-javascript/



Happy Coding!

No comments:

Post a Comment