Strange observation on nodejs infinite loop functi

2019-09-02 07:03发布

问题:

I recently came across the article Tail call optimization in ECMAScript 6. I was interested in testing the TCO behavior (Even though I later found that the TCO was not supported by nodejs 8+ as mentioned by the article) and found behavior that I could not understand.

  1. Plain loop function

    'use strict';
    
    process.on('SIGTERM', () =>
    {
        console.log('SIGTERM received');
        process.exit(0);
    })
    
    process.on('SIGINT', () =>
    {
        console.log('SIGINT received');
        process.exit(0);
    })
    
    process.on('uncaughtException', (error) =>
    {
        console.error('Uncaught exception', error);
        process.exit(1);
    })
    
    process.on('unhandledRejection', (error) =>
    {
        console.error('Unhandled rejection', error);
        process.exit(0);
    })
    
    let counter = 0;
    
    function test()
    {
        console.log(`Counter: ${counter++}`);
        test();
    }
    
    console.log('Test started');
    
    test();
    
    console.log('Test ended');
    

    This version of code produces:

    Test started
    Counter: 0
    ...
    Counter: 10452
    Uncaught exception RangeError: Maximum call stack size exceeded
        at WriteStream.removeListener (events.js:306:28)
        at write (console.js:130:12)
        at Console.log (console.js:135:3)
        at test (/test.js:31:13)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
        at test (/test.js:32:5)
    
  2. Async loop function without any await within the function

    'use strict';
    
    process.on('SIGTERM', () =>
    {
        console.log('SIGTERM received');
        process.exit(0);
    })
    
    process.on('SIGINT', () =>
    {
        console.log('SIGINT received');
        process.exit(0);
    })
    
    process.on('uncaughtException', (error) =>
    {
        console.error('Uncaught exception', error);
        process.exit(1);
    })
    
    process.on('unhandledRejection', (error) =>
    {
        console.error('Unhandled rejection', error);
        process.exit(0);
    })
    
    let counter = 0;
    
    async function test()
    {
        console.log(`Counter: ${counter++}`);
        test();
    }
    
    console.log('Test started');
    
    test();
    
    console.log('Test ended'); 
    

    This version of code produces:

    Test started
    Counter: 0
    ...
    Counter: 6967
    Test ended
    
  3. Async loop function with await within the function

    'use strict';
    
    const bluebird = require('bluebird');
    
    process.on('SIGTERM', () =>
    {
        console.log('SIGTERM received');
        process.exit(0);
    })
    
    process.on('SIGINT', () =>
    {
        console.log('SIGINT received');
        process.exit(0);
    })
    
    process.on('uncaughtException', (error) =>
    {
        console.error('Uncaught exception', error);
        process.exit(1);
    })
    
    process.on('unhandledRejection', (error) =>
    {
        console.error('Unhandled rejection', error);
        process.exit(0);
    })
    
    let counter = 0;
    
    async function test()
    {
        await bluebird.delay(1);
        console.log(`Counter: ${counter++}`);
        test();
    }
    
    console.log('Test started');
    
    test();
    
    console.log('Test ended');
    

    This version of code runs non-stop.

In Summary:

  1. plain loop function: stops at counter 10452 and throws RangeError: Maximum call stack size exceeded
  2. Async loop function without any await within the function: stops at counter 6967 without any error
  3. Async loop function with await within the function: runs non-stop

Can anyone explain this behavior differences or point me to any keyword i can google?