javascript - 暂停、恢复、中止和解决长期运行的 promise

标签 javascript node.js recursion promise

我的 Controller 能够暂停、恢复和解决长期运行的 promise 。 当我的 Controller 中止 Promise 时,不知何故我的 Controller 递归循环被破坏了。

我前几天了解了 Promise,所以可能我不明白拒绝或捕获的一些内容。

首先,可以在 promise 链的步骤之间检查一个状态变量。

var state = "idle"

可以插入一个垫片 promise 来检查此状态变量

// insert this shim before each link of promise chain
function promise_to_check_pause_and_abort(x) {
    if (state == "running") {
        return Promise.resolve(x) // just keep going 
    } else if (state == "pause") {
        let P = new Promise((resolve, reject) => {
            let resume_cb = () => { resolve() }
            pause_cb_queue.push(resume_cb)
        });
        return P;
    } else if (state == "abort") {
        return Promise.reject("aborted at stage " + x)
    } else {
        return promise.reject("should not be executing in this invalid state = " + state)
    }
}

我的真实应用程序运行许多链式 promise ,可能需要 15 分钟以上才能完成。这不需要证明我的问题。所以这是一个返回 promise 的简单假任务。

function promise_to_do_something_long_running(n) {
    if (isNaN(n)) {
        n = 0;
    }

    if (n == 100) {
        return Promise.resolve("done")

    } else {
        let P = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("doing " + n);
                resolve();
            }, 100)
        })

        return P
            .then(() => { return promise_to_check_pause_and_abort(n) })
            .then(() => { return promise_to_do_something_long_running(n + 1) })
    }

}

现在是一个简单的文本 Controller ,用于启动、暂停、恢复和中止上述长期运行的 promise 。

// A recursive controller. 
//   Get response based on current running state.
//   Regardless of response, do it again.
function controller() {

    if (state == "running") {
        rl.question("abort or pause :", (answer) => {

            if (answer == "abort") {
                state = "abort"
            } else if (answer == "pause") {
                state = "pause"
            };

            controller(); // regardless of response or state, get input again
        })

    } else if (state == "pause") {
        rl.question("abort or resume :", (answer) => {

            if (answer == "abort") {
                state = "abort";
                pause_cb_queue.forEach((cb) => { cb() })
                pause_cb_queue = []
            } else if (answer == "resume") {
                state = "running"
                pause_cb_queue.forEach((cb) => { cb() })
                pause_cb_queue = []
            };

            controller(); // regardless of response or state, get input again
        })

    } else if (state == "idle") {

        rl.question("start :", (answer) => {

            if (answer == "start") {
                state = "running";

                // controller loop not dependent on resolution of this
                // only state is 
                promise_to_do_something_long_running()
                    .then((a) => {
                        console.log("completed task, response :" + a);
                        state = "idle"
                    })
                    .catch((b) => {
                        console.log("task rejected with response :" + b);
                        state = "idle"
                    });
            };

            controller(); // regardless of response or state, get input again
        })
    }

}


controller();

一切都很完美,除了当我中止时, Controller 递归中断并且不再向用户请求输入。如何执行

.catch((b) => {
                        console.log("task rejected with response :" + b);
                        state = "idle"
                    });

导致外部 Controller 递归停止?

在nodejs中运行的完整代码如下:

'use strict';


const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

var state = "idle"
var pause_cb_queue = []


// insert this shim before each link of promise chain
function promise_to_check_pause_and_abort(x) {
    if (state == "running") {
        return Promise.resolve(x) // just keep going 
    } else if (state == "pause") {
        let P = new Promise((resolve, reject) => {
            let resume_cb = () => { resolve() }
            pause_cb_queue.push(resume_cb)
        });
        return P;
    } else if (state == "abort") {
        return Promise.reject("aborted at stage " + x)
    } else {
        return promise.reject("should not be executing in this invalid state = " + state)
    }
}

function promise_to_do_something_long_running(n) {
    if (isNaN(n)) {
        n = 0;
    }

    if (n == 100) {
        return Promise.resolve("done")

    } else {
        let P = new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log("doing " + n);
                resolve();
            }, 100)
        })

        return P
            .then(() => { return promise_to_check_pause_and_abort(n) })
            .then(() => { return promise_to_do_something_long_running(n + 1) })
    }

}

// A recursive controller. 
//   Get response based on current running state.
//   Regardless of response, do it again.
function controller() {

    if (state == "running") {
        rl.question("abort or pause :", (answer) => {

            if (answer == "abort") {
                state = "abort"
            } else if (answer == "pause") {
                state = "pause"
            };

            controller(); // regardless of response or state, get input again
        })

    } else if (state == "pause") {
        rl.question("abort or resume :", (answer) => {

            if (answer == "abort") {
                state = "abort";
                pause_cb_queue.forEach((cb) => { cb() })
                pause_cb_queue = []
            } else if (answer == "resume") {
                state = "running"
                pause_cb_queue.forEach((cb) => { cb() })
                pause_cb_queue = []
            };

            controller(); // regardless of response or state, get input again
        })

    } else if (state == "idle") {

        rl.question("start :", (answer) => {

            if (answer == "start") {
                state = "running";

                // controller loop not dependent on resolution of this
                // only state is 
                promise_to_do_something_long_running()
                    .then((a) => {
                        console.log("completed task, response :" + a);
                        state = "idle"
                    })
                    .catch((b) => {
                        console.log("task rejected with response :" + b);
                        state = "idle"
                    });
            };

            controller(); // regardless of response or state, get input again
        })
    }

}


controller();

最佳答案

暂停和恢复 promise 并没有什么问题。我的错误是缺少处理 Controller 中的中止状态。

    } else if (state == "abort") {
        rl.question("in abort state, no valid input :", (answer) => {
            controller(); // regardless of response or state, get input again
        })

有了上面的补充,一切就完美了。我现在可以暂停 promise 链。

关于javascript - 暂停、恢复、中止和解决长期运行的 promise ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46308127/

相关文章:

javascript - 如何在CKEditor5中设置选择?

javascript - 简单的 CORS 不起作用(即使它应该)

javascript - 按父 ids 对象 Ramda 分组数组

node.js - 在node.js中创建自定义沙箱(只能在某个目录中读取,不能在任何地方写入)

javascript - 发送 html+css 作为响应的简单 node.js 服务器

java - 了解使用数组中所有可能组合的递归

swift - 将递归异步函数转换为 promise

javascript - 运行脚本以禁用脚本

mysql - 当 node js 中的 mysql 数据库更改时通知

ms-access - 是否可以在Access中创建递归查询?