Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在一段时间后停止执行包含无限循环的Javascript函数_Javascript_Infinite Loop - Fatal编程技术网

如何在一段时间后停止执行包含无限循环的Javascript函数

如何在一段时间后停止执行包含无限循环的Javascript函数,javascript,infinite-loop,Javascript,Infinite Loop,假设我有一段包含无限循环的代码: function infiniteLoop() { while(true) { //do something, eg. document.getElementById("someID").innerHTML = "Blah"; } } 如果我们在在线编译器中执行此代码,浏览器将崩溃。我想防止这种情况发生。因此,我尝试了以下代码: 此代码不会使浏览器崩溃,因为我在clearInterval(myVar)调用infi

假设我有一段包含无限循环的代码:

function infiniteLoop() {
    while(true) {
        //do something, eg.
        document.getElementById("someID").innerHTML = "Blah";
    }
}
如果我们在在线编译器中执行此代码,浏览器将崩溃。我想防止这种情况发生。因此,我尝试了以下代码:

此代码不会使浏览器崩溃,因为我在
clearInterval(myVar)
调用
infiniteLop()
之前停止执行

我的问题是,如果这些函数在一段时间内没有响应(例如,在5秒之后或浏览器崩溃之前),我如何停止执行这些函数

例如,如果我们在中复制粘贴以下java代码

我们得到一个很好的输出,说

脚本执行时间超过5秒,因此被终止


这是我当前的代码:

这有点棘手,但完全可行。您需要对脚本进行标记化,然后重新生成脚本,但在每个循环和函数调用中插入一个计数器增量。如果计数器超过某个阈值,则爆炸。我在这里做到了:

您可以在以下位置查看源代码:

有趣的部分在wrapper.js()中

谷歌escodegen、estraverse和esprima

我非常依赖这一点:

wrapper.js,根据要求:

// Don't obfuscate this file! We depend on the toString() of functions!
// this was all nicked from https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js

(function(mainApp) {

    'use strict';
    var esprima = window.esprima,
        estraverse = window.estraverse,
        escodegen = window.escodegen,
        errors = [],
        eng,
        Syntax = estraverse.Syntax;

    // This implements the jankiest possible "source map", where we keep an array
    // of [generatedLine, knownSourceLine]. Seems to essentially work.
    function SourceNode(line, col, _sourceMap, generated) {
        this.line = line;
        this.col = col;
        this.generated = generated;
    }

    SourceNode.prototype.toStringWithSourceMap = function toStringWithSourceMap() {
        var code = [];
        var mapLines = {};
        var map = [];
        // assumes that wrapCode adds two lines
        var line = 3;
        var lastMapLine = null;

        function walk(node) {
            if (typeof(node) === "string") {
                if (node) {
                    code.push(node);
                    var matches = node.match(/\n/g);
                    if (matches !== null) {
                        line += matches.length;
                    }
                }
            } else if (node instanceof SourceNode) {
                if (node.line !== null) {
                    if (!mapLines[line]) {
                        map.push([line, node.line]);
                        mapLines[line] = node.line;
                    }
                }
                walk(node.generated);
            } else {
                node.forEach(walk);
            }
        }
        walk(this);
        return {
            code: code.join(''),
            map: map
        };
    };

    SourceNode.prototype.toString = function toString() {
        return this.toStringWithSourceMap().code;
    };

    // This is used by escodegen
    window.sourceMap = {
        SourceNode: SourceNode
    };

    // TODO (chs): add in all the things that need to be masked
    function runWrapper($userCode, __sys) {
        var clear = __sys.clear,
            setpixel = __sys.setpixel,
            rectangle = __sys.rectangle,
            box = __sys.box,
            line = __sys.line,
            getpixel = __sys.getpixel,
            getpixeli = __sys.getpixeli,
            keypress = __sys.keypress,
            keyrelease = __sys.keyrelease,
            keyheld = __sys.keyheld,
            reset = __sys.reset;
        __sys.userFunction = __sys.catchErrors($userCode);
    }

    function extractCode(fn) {
        var code = fn.toString();
        return code.substring(code.indexOf('{') + 1, code.lastIndexOf('}'));
    }

    function makeOneLine(code) {
        return code.replace(/(\/\/[^\n]+|\n\s|\r\n\s*)/g, '');
    }

    var runTemplate = makeOneLine(extractCode(runWrapper));

    function wrapCode(code, template, functionName, postCode) {
        // avoid interpretation of the replacement string by using a fun.
        // otherwise mo' $ mo problems.
        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter
        return ("'use strict';" + template.replace(/\$userCode/, function() {
            return 'function ' + functionName + '() {\n' + code + postCode + '\n}';
        }));
    }

    var injectStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?');").body[0];
    var injectElseStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?'); else ;").body[0];

    function CallExpression(callee, args) {
        this.callee = callee;
        this.arguments = args;
    }
    CallExpression.prototype.type = Syntax.CallExpression;

    function Identifier(name) {
        this.name = name;
    }
    Identifier.prototype.type = Syntax.Identifier;

    function BlockStatement(body) {
        this.body = body;
    }
    BlockStatement.prototype.type = Syntax.BlockStatement;

    function ReturnStatement(argument) {
        this.argument = argument;
    }
    ReturnStatement.prototype.type = Syntax.ReturnStatement;

    function FunctionExpression(id, params, body) {
        this.id = id;
        this.params = params;
        this.body = body;
        this.defaults = [];
        this.expression = false;
        this.generator = false;
        this.rest = null;
    }
    FunctionExpression.prototype.type = Syntax.FunctionExpression;

    function wrapId(node, defaultName) {
        if (node.loc) {
            var id = (node.id || {
                name: null,
                loc: null
            });
            var loc = id.loc || node.loc;
            var name = id.name || defaultName;
            return new Identifier(name + '$' + loc.start.line);
        } else {
            return node.id;
        }
    }

    function instrumentAST(ast) {
        var identifierStack = [];

        function pushIdentifier(s) {
            identifierStack[identifierStack.length - 1].push(s);
        }

        function popIdentifierStack() {
            identifierStack.pop();
        }

        function pushIdentifierStack() {
            identifierStack.push([]);
        }

        function peekLastIdentifier() {
            var lastStackIdx = identifierStack.length - 1;
            if (lastStackIdx >= 0) {
                var stack = identifierStack[lastStackIdx];
                if (stack.length) {
                    return stack[stack.length - 1];
                }
            }
            return '';
        }
        pushIdentifierStack();
        return estraverse.replace(ast, {
            enter: function enterAST(node) {
                switch (node.type) {
                    case Syntax.VariableDeclarator:
                        if (node.id.type === Syntax.Identifier) {
                            pushIdentifier(node.id.name);
                        }
                        break;
                    case Syntax.MemberExpression:
                        if (node.object.type === Syntax.Identifier) {
                            var id = node.object.name;
                            if (node.property.type === Syntax.Identifier) {
                                id += '__dot__' + node.property.name;       // huh? why mangle these?
                                // console.log(id);
                            }
                            pushIdentifier(id);
                        } else if (node.property.type === Syntax.Identifier) {
                            pushIdentifier(node.property.name);
                        }
                        break;
                    case Syntax.FunctionDeclaration:
                        pushIdentifierStack();
                        break;
                    case Syntax.FunctionExpression:
                        pushIdentifierStack();
                        break;
                    default:
                        break;
                }
                return node;
            },
            leave: function leaveAST(node) {
                switch (node.type) {
                    case Syntax.DoWhileStatement:
                        break;
                    case Syntax.ForStatement:
                        break;
                    case Syntax.FunctionDeclaration:
                        break;
                    case Syntax.FunctionExpression:
                        break;
                    case Syntax.WhileStatement:
                        break;
                    default:
                        return estraverse.SKIP;
                }
                // modify the BlockStatement in-place to inject the instruction counter

                if(node.body.body === undefined) {
                    // they have used a non-block statement as the body of a function or loop construct

                    // not allowed for function declarations - should never get here
                    if(node.type === Syntax.FunctionDeclaration) {
                        errors.push({
                            message: "Missing {",
                            line: node.loc.start.line,
                            column: node.loc.start.column
                        });
                    }
                    else {
                        // otherwise insert the test
                        var newBody = angular.copy(injectElseStatement);
                        newBody.alternate = node.body;
                        node.body = newBody;
                    }
                    return estraverse.SKIP;
                }

                node.body.body.unshift(injectStatement);
                if (node.type === Syntax.FunctionExpression) {
                    popIdentifierStack();
                    // __catchErrors(node)
                    node.id = wrapId(node, peekLastIdentifier());
                    return new CallExpression(
                        new Identifier("__sys.catchErrors"), [node]);
                }
                if (node.type === Syntax.FunctionDeclaration) {
                    popIdentifierStack();
                    // modify the BlockStatement in-place to be
                    // return __catchErrors(function id() { body });
                    var funBody = node.body;
                    node.body = new BlockStatement([
                        new ReturnStatement(
                            new CallExpression(
                                new CallExpression(
                                    new Identifier("__sys.catchErrors"), [new FunctionExpression(
                                        wrapId(node, peekLastIdentifier()), [],
                                        funBody)]), []))
                    ]);
                }
                return node;
            }
        });
    }

    // mainApp.sandbox('var a = 1; function update(frame) { clear(0); }').code

    // give it the source code as a string
    mainApp.sandbox = function(code) {
        var rc = {};
        this.errors = [];
        try {
            this.ast = instrumentAST(esprima.parse(code, { range: true, loc: true }));
            this.map = escodegen.generate(this.ast, { sourceMap: true, sourceMapWithCode: true });
            this.code = wrapCode(this.map.code, runTemplate, '', ';\n__sys.updateFunction = (typeof update === "function") ? update : null;');
        }
        catch(e) {
            this.errors.push({
                message: e.description,
                line: e.lineNumber,
                column: e.column
            });
        }
        if(this.code) {
            this.code = "eng.clientFunction = function(__sys) {" + this.code + "};";
        }
    };

    mainApp.sandbox.prototype.searchMap = function(needle) {
        // binary search
        var lo = 0;
        var hi = this.map.map.length;
        var mid, here;
        while (true) {
            mid = lo + ((hi - lo) >> 1);
            here = this.map.map[mid];
            if (mid === lo || here[0] === needle) {
                return here[1];
            } else if (here[0] > needle) {
                hi = mid;
            } else {
                lo = mid;
            }
        }
    };

})(mainApp);

这有点棘手,但完全可行。您需要对脚本进行标记化,然后重新生成脚本,但在每个循环和函数调用中插入一个计数器增量。如果计数器超过某个阈值,则爆炸。我在这里做到了:

您可以在以下位置查看源代码:

有趣的部分在wrapper.js()中

谷歌escodegen、estraverse和esprima

我非常依赖这一点:

wrapper.js,根据要求:

// Don't obfuscate this file! We depend on the toString() of functions!
// this was all nicked from https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js

(function(mainApp) {

    'use strict';
    var esprima = window.esprima,
        estraverse = window.estraverse,
        escodegen = window.escodegen,
        errors = [],
        eng,
        Syntax = estraverse.Syntax;

    // This implements the jankiest possible "source map", where we keep an array
    // of [generatedLine, knownSourceLine]. Seems to essentially work.
    function SourceNode(line, col, _sourceMap, generated) {
        this.line = line;
        this.col = col;
        this.generated = generated;
    }

    SourceNode.prototype.toStringWithSourceMap = function toStringWithSourceMap() {
        var code = [];
        var mapLines = {};
        var map = [];
        // assumes that wrapCode adds two lines
        var line = 3;
        var lastMapLine = null;

        function walk(node) {
            if (typeof(node) === "string") {
                if (node) {
                    code.push(node);
                    var matches = node.match(/\n/g);
                    if (matches !== null) {
                        line += matches.length;
                    }
                }
            } else if (node instanceof SourceNode) {
                if (node.line !== null) {
                    if (!mapLines[line]) {
                        map.push([line, node.line]);
                        mapLines[line] = node.line;
                    }
                }
                walk(node.generated);
            } else {
                node.forEach(walk);
            }
        }
        walk(this);
        return {
            code: code.join(''),
            map: map
        };
    };

    SourceNode.prototype.toString = function toString() {
        return this.toStringWithSourceMap().code;
    };

    // This is used by escodegen
    window.sourceMap = {
        SourceNode: SourceNode
    };

    // TODO (chs): add in all the things that need to be masked
    function runWrapper($userCode, __sys) {
        var clear = __sys.clear,
            setpixel = __sys.setpixel,
            rectangle = __sys.rectangle,
            box = __sys.box,
            line = __sys.line,
            getpixel = __sys.getpixel,
            getpixeli = __sys.getpixeli,
            keypress = __sys.keypress,
            keyrelease = __sys.keyrelease,
            keyheld = __sys.keyheld,
            reset = __sys.reset;
        __sys.userFunction = __sys.catchErrors($userCode);
    }

    function extractCode(fn) {
        var code = fn.toString();
        return code.substring(code.indexOf('{') + 1, code.lastIndexOf('}'));
    }

    function makeOneLine(code) {
        return code.replace(/(\/\/[^\n]+|\n\s|\r\n\s*)/g, '');
    }

    var runTemplate = makeOneLine(extractCode(runWrapper));

    function wrapCode(code, template, functionName, postCode) {
        // avoid interpretation of the replacement string by using a fun.
        // otherwise mo' $ mo problems.
        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter
        return ("'use strict';" + template.replace(/\$userCode/, function() {
            return 'function ' + functionName + '() {\n' + code + postCode + '\n}';
        }));
    }

    var injectStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?');").body[0];
    var injectElseStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?'); else ;").body[0];

    function CallExpression(callee, args) {
        this.callee = callee;
        this.arguments = args;
    }
    CallExpression.prototype.type = Syntax.CallExpression;

    function Identifier(name) {
        this.name = name;
    }
    Identifier.prototype.type = Syntax.Identifier;

    function BlockStatement(body) {
        this.body = body;
    }
    BlockStatement.prototype.type = Syntax.BlockStatement;

    function ReturnStatement(argument) {
        this.argument = argument;
    }
    ReturnStatement.prototype.type = Syntax.ReturnStatement;

    function FunctionExpression(id, params, body) {
        this.id = id;
        this.params = params;
        this.body = body;
        this.defaults = [];
        this.expression = false;
        this.generator = false;
        this.rest = null;
    }
    FunctionExpression.prototype.type = Syntax.FunctionExpression;

    function wrapId(node, defaultName) {
        if (node.loc) {
            var id = (node.id || {
                name: null,
                loc: null
            });
            var loc = id.loc || node.loc;
            var name = id.name || defaultName;
            return new Identifier(name + '$' + loc.start.line);
        } else {
            return node.id;
        }
    }

    function instrumentAST(ast) {
        var identifierStack = [];

        function pushIdentifier(s) {
            identifierStack[identifierStack.length - 1].push(s);
        }

        function popIdentifierStack() {
            identifierStack.pop();
        }

        function pushIdentifierStack() {
            identifierStack.push([]);
        }

        function peekLastIdentifier() {
            var lastStackIdx = identifierStack.length - 1;
            if (lastStackIdx >= 0) {
                var stack = identifierStack[lastStackIdx];
                if (stack.length) {
                    return stack[stack.length - 1];
                }
            }
            return '';
        }
        pushIdentifierStack();
        return estraverse.replace(ast, {
            enter: function enterAST(node) {
                switch (node.type) {
                    case Syntax.VariableDeclarator:
                        if (node.id.type === Syntax.Identifier) {
                            pushIdentifier(node.id.name);
                        }
                        break;
                    case Syntax.MemberExpression:
                        if (node.object.type === Syntax.Identifier) {
                            var id = node.object.name;
                            if (node.property.type === Syntax.Identifier) {
                                id += '__dot__' + node.property.name;       // huh? why mangle these?
                                // console.log(id);
                            }
                            pushIdentifier(id);
                        } else if (node.property.type === Syntax.Identifier) {
                            pushIdentifier(node.property.name);
                        }
                        break;
                    case Syntax.FunctionDeclaration:
                        pushIdentifierStack();
                        break;
                    case Syntax.FunctionExpression:
                        pushIdentifierStack();
                        break;
                    default:
                        break;
                }
                return node;
            },
            leave: function leaveAST(node) {
                switch (node.type) {
                    case Syntax.DoWhileStatement:
                        break;
                    case Syntax.ForStatement:
                        break;
                    case Syntax.FunctionDeclaration:
                        break;
                    case Syntax.FunctionExpression:
                        break;
                    case Syntax.WhileStatement:
                        break;
                    default:
                        return estraverse.SKIP;
                }
                // modify the BlockStatement in-place to inject the instruction counter

                if(node.body.body === undefined) {
                    // they have used a non-block statement as the body of a function or loop construct

                    // not allowed for function declarations - should never get here
                    if(node.type === Syntax.FunctionDeclaration) {
                        errors.push({
                            message: "Missing {",
                            line: node.loc.start.line,
                            column: node.loc.start.column
                        });
                    }
                    else {
                        // otherwise insert the test
                        var newBody = angular.copy(injectElseStatement);
                        newBody.alternate = node.body;
                        node.body = newBody;
                    }
                    return estraverse.SKIP;
                }

                node.body.body.unshift(injectStatement);
                if (node.type === Syntax.FunctionExpression) {
                    popIdentifierStack();
                    // __catchErrors(node)
                    node.id = wrapId(node, peekLastIdentifier());
                    return new CallExpression(
                        new Identifier("__sys.catchErrors"), [node]);
                }
                if (node.type === Syntax.FunctionDeclaration) {
                    popIdentifierStack();
                    // modify the BlockStatement in-place to be
                    // return __catchErrors(function id() { body });
                    var funBody = node.body;
                    node.body = new BlockStatement([
                        new ReturnStatement(
                            new CallExpression(
                                new CallExpression(
                                    new Identifier("__sys.catchErrors"), [new FunctionExpression(
                                        wrapId(node, peekLastIdentifier()), [],
                                        funBody)]), []))
                    ]);
                }
                return node;
            }
        });
    }

    // mainApp.sandbox('var a = 1; function update(frame) { clear(0); }').code

    // give it the source code as a string
    mainApp.sandbox = function(code) {
        var rc = {};
        this.errors = [];
        try {
            this.ast = instrumentAST(esprima.parse(code, { range: true, loc: true }));
            this.map = escodegen.generate(this.ast, { sourceMap: true, sourceMapWithCode: true });
            this.code = wrapCode(this.map.code, runTemplate, '', ';\n__sys.updateFunction = (typeof update === "function") ? update : null;');
        }
        catch(e) {
            this.errors.push({
                message: e.description,
                line: e.lineNumber,
                column: e.column
            });
        }
        if(this.code) {
            this.code = "eng.clientFunction = function(__sys) {" + this.code + "};";
        }
    };

    mainApp.sandbox.prototype.searchMap = function(needle) {
        // binary search
        var lo = 0;
        var hi = this.map.map.length;
        var mid, here;
        while (true) {
            mid = lo + ((hi - lo) >> 1);
            here = this.map.map[mid];
            if (mid === lo || here[0] === needle) {
                return here[1];
            } else if (here[0] > needle) {
                hi = mid;
            } else {
                lo = mid;
            }
        }
    };

})(mainApp);

通常所有JavaScript都在一个线程中运行,因此不可能在循环运行时运行任何可能停止循环的JavaScript。使用,可以在单独的线程中运行无限循环,然后可以终止它:

var myWorker = new Worker( '/infinite.js ');
setTimeout( function ( ) {
    myWorker.terminate( );
}, 5000 );

但是,您的web工作人员将无法访问DOM,因此无限循环的内容需要与您的问题内容不同。

通常所有JavaScript都在一个线程中运行,因此不可能在循环运行时运行任何可能停止循环的JavaScript。使用,可以在单独的线程中运行无限循环,然后可以终止它:

var myWorker = new Worker( '/infinite.js ');
setTimeout( function ( ) {
    myWorker.terminate( );
}, 5000 );

但是,您的web工作者将无法访问DOM,因此您的无限循环的内容需要与您的问题不同。

我在Bergi的评论中找到了我想要的内容


或者,放置一个
if(Date.now()>dateAtStartOfExecution+5000)返回在每个循环体中

现在我的代码看起来像:

function infiniteLoop() {
    dateAtStartOfExecution = Date.now();
    while(true) {
        //do something
        document.getElementById("someID").innerHTML = "Blah";
        if (Date.now() > dateAtStartOfExecution+5000) {
            alert("Taking too much time. Killing.");
            return;
        }
    }
}
如果我在5秒钟后运行此代码,我将收到警报,执行将停止。试试这个:
我在Bergi的评论中找到了我想要的东西


或者,放置一个
if(Date.now()>dateAtStartOfExecution+5000)返回在每个循环体中

现在我的代码看起来像:

function infiniteLoop() {
    dateAtStartOfExecution = Date.now();
    while(true) {
        //do something
        document.getElementById("someID").innerHTML = "Blah";
        if (Date.now() > dateAtStartOfExecution+5000) {
            alert("Taking too much time. Killing.");
            return;
        }
    }
}
如果我在5秒钟后运行此代码,我将收到警报,执行将停止。试试这个:

您能在回答中包含相关的JavaScript代码吗?你的bitbucket链接需要登录。你可以减少代码来展示你正在推广的技术。这很公平。我看到你在底部的
循环中描述了什么。你能在回答中包含相关的JavaScript代码吗?你的bitbucket链接需要登录。你可以减少代码来展示你正在推广的技术。这很公平。我看到您在底部的
循环中描述的内容。非常感谢您的回答。现在说得更有道理了:)非常感谢你的回答。现在更有意义了:)或者,放置一个
if(Date.now()>dateAtStartOfExecution+5000)返回在每个循环体中。@BergiYahoo!!!这正是我想要的。非常感谢:)或者,放置一个
if(Date.now()>dateAtStartOfExecution+5000)返回在每个循环体中。@BergiYahoo!!!这正是我想要的。非常感谢:)