Run NodeJS event loop / wait for child process to finish

前端 未结 4 1079
暖寄归人
暖寄归人 2021-02-04 11:01

I first tried a general description of the problem, then some more detail why the usual approaches don\'t work. If you would like to read these abstracted explanations go on

4条回答
  •  Happy的楠姐
    2021-02-04 11:22

    Adding a third ( :) ) solution to your problem after you clarified what behavior you seek I suggest using Fibers.

    Fibers let you do co-routines in nodejs. Coroutines are functions that allow multiple entry/exit points. This means you will be able to yield control and resume it as you please.

    Here is a sleep function from the official documentation that does exactly that, sleep for a given amount of time and perform actions.

    function sleep(ms) {
        var fiber = Fiber.current;
        setTimeout(function() {
            fiber.run();
        }, ms);
        Fiber.yield();
    }
    
    Fiber(function() {
        console.log('wait... ' + new Date);
        sleep(1000);
        console.log('ok... ' + new Date);
    }).run();
    console.log('back in main');
    

    You can place the code that does the waiting for the resource in a function, causing it to yield and then run again when the task is done.

    For example, adapting your example from the question:

    var pausedExecution, importantData;
    function getImportantData() {
        while (importantData === undefined) {
            pausedExecution = Fiber.current;
            Fiber.yield();
            pausedExecution = undefined;
        }
    
        if (importantData === null) {
            throw new Error("Data could not be generated.");
        } else {
            // we should have proper data now
            return importantData;
        }
    }
    
    function callback(partialDataMessage) {
        if (partialDataMessage.needsCorrection) {
            var theData = getImportantData();
            // use data to correct message
            process.send(correctedMessage); // send corrected result to main process
        } else {
            process.send(partialDataMessage); // send unmodified result to main process
        }
    }
    
    function executeCode(code) {
        // setup child process to calculate the data
        importantDataCalculator = fork("./runtime");
        importantDataCalculator.on("message", function (msg) {
            if (msg.type === "result") {
                importantData = msg.data;
            } else if (msg.type === "error") {
                importantData = null;
            } else {
                throw new Error("Unknown message from dataGenerator!");
            }
    
            if (pausedExecution) {
                // execution is waiting for the data
                pausedExecution.run();
            }
        });
    
    
        // wrap the execution of the code in a Fiber, so it can be paused
        Fiber(function () {
            runCodeWithCallback(code, callback); // the callback will be called from time to time when the code produces new data
            // this callback is synchronous and blocking,
            // but it will yield control to the event loop if it has to wait for the child-process to finish
        }).run();
    }
    

    Good luck! I always say it is better to solve one problem in 3 ways than solving 3 problems the same way. I'm glad we were able to work out something that worked for you. Admittingly, this was a pretty interesting question.

提交回复
热议问题