我的 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/