Executing multiple "code", arriving asynchronously, using vm.runInNewContext to run in a single process

Viewed 56

I observed the following when running vm.runInNewContext:

   vm = require('vm');
   fs = require('fs');

   function f() {for (l=0;l<1000;++l) {var ll=l*l*l; console.log(1);}};
   function g() { console.log(2)};
   vm.runInNewContext( 'for (i=0;i<1000;++i) { fs.writeFile("/tmp/1_", "111", f); }' ,
                 {fs:fs, f:f, console:{log(){console.log.apply(console,arguments);}}}, 
             {timeout:5000});

   vm.runInNewContext( 'for (j=0;j<1000;++j) { fs.writeFile("/tmp/1_", "222", g); }' ,
                 {fs:fs, g:g, console:{log(){console.log.apply(console,arguments);}}}, 
             {timeout:5000});

I would have expected the output to be interspersed with 1 and 2 but all the 1s are displayed first and then the 2s. In actual use, the code is sent asynchronously over the network to be executed in the vm and if one is in progress, it appears that the execution of the subsequent invocation will be delayed, even though the first code has async i/o calls. Is that correct? Any way to get around it. The code passed to vm will most likely use multiple promises with async i/o.

1 Answers

this is related to nodejs eventloop. for/while loop in nodejs blocks eventloop thus any further code is not going to be executed till it ends. I can't explain here more since its event loop is different topic from original question.

By wrapping for loop inside async you can avoid blocking event-loop.

Here is code that prints 1 & 2 interspersed as you expected and yes I had to ripoff some code to keep things simple.

const vm  = require('vm')

const code1 = `
(async function(){
  for (i=0;i<5;++i) await Promise.resolve(console.log(1))
})()
`

const code2 = `
(async function(){
  for (i=0;i<5;++i) await Promise.resolve(console.log(2))
})()
`
vm.runInNewContext(code1, { console }, { timeout: 5000 })

vm.runInNewContext(code2, { console }, { timeout: 5000 })

output

1
2
1
2
1
2
1
2
1
2
Related