在我的Web应用程序中,我可以运行代码块(它创建一个Promise,然后等待结果出来)。每次用户运行一个段落时,我都会将其ID添加到数组中并按顺序运行。
runSequentially(paragraphsId) {
paragraphsId.reduce((promise, paragraphId) => {
return promise.then(() => this.runParagraph(paragraphId))
}, Promise.resolve())
}
addToQueue(paragraphId) {
if (this.state.runQueue.indexOf(paragraphId) === -1) {
this.setState({
runQueue: [...this.state.runQueue, paragraphId]
}, () => this.runSequentially(this.state.runQueue))
}
}
runParagraph(paragraphId) {
const newParagraphResults = { ...this.state.paragraphResults }
delete newParagraphResults[paragraphId]
const newParagraphs = { ...this.state.paragraphs }
const newParagraph = newParagraphs[paragraphId]
newParagraph.isRunning = true
newParagraph.status = 'running'
this.setState({
paragraphs: newParagraphs,
paragraphResults: newParagraphResults
})
const paragraphs = [
{
identifiers: { id: paragraphId },
title: newParagraph.title,
source: newParagraph.source
}
]
const notebookLibraries = Object.values(this.state.notebookLibraries)
this.runController = new AbortController()
return this.service.notebookRun(this.notebookId, paragraphs, notebookLibraries, this.runController)
.then(result => {
Object.entries(result.paragraphs).forEach(entry => {
if (entry[0] === 'default_paragraph') {
return
}
const paragraphId = entry[0]
const paragraphResult = entry[1]
newParagraphResults[paragraphId] = paragraphResult
paragraphResult.exception ? this.setParagraph(paragraphId, { status: 'failed' }) :
this.setParagraph(paragraphId, { status: 'passed' })
})
this.setState({ paragraphResults: newParagraphResults })
})
.catch((error) => {
if (error.name === 'AbortError') {
return Promise.reject(error)
}
const message = `Execution failed for reason: ${error.reason}.`
this.handleServiceError('notebook', 'run', message)
})
.finally(() => {
const newRunQueue = [ ...this.state.runQueue ]
newRunQueue.shift()
this.setParagraph(paragraphId, { isRunning: false })
this.setState({ runQueue: newRunQueue })
})
}
当用户运行段落时,我们调用addToQueue
,然后调用runSequentially
。我们在达成承诺时(在runParagraph
方法中转移了队列,但是如果我们在第一个段落完成之前运行另一个段落,它将对相同的承诺进行两次迭代。
您将如何处理动态的Promise队列?递归在这种情况下可以工作吗?
答案 0 :(得分:2)
您应该在班级中初始化另一个属性(也许queue
不是最好的名称,因为您已经拥有state.runQueue
),并将其设为Promise.resolve()
,并将其作为序列的未完成承诺队列。然后您可以执行以下操作:
runSequentially(...paragraphsId) {
this.queue = paragraphsId.reduce((promise, paragraphId) => {
return promise.then(() => this.runParagraph(paragraphId))
}, this.queue)
}
addToQueue(paragraphId) {
if (this.state.runQueue.indexOf(paragraphId) === -1) {
this.setState({
runQueue: [...this.state.runQueue, paragraphId]
}, () => this.runSequentially(paragraphId))
}
}
runSequentially()
现在接受增量更新,而不是整个runQueue
,并且您不应该将queue
存储在您的state
变量中,因为承诺本身不会影响您渲染,所以很安全。
答案 1 :(得分:2)
如果我们在第一个段落完成之前运行另一个段落,这将对相同的诺言进行两次迭代。
您需要将promise
队列作为属性保留在您的状态,而不是每次调用Promise.resolve()
时都创建一个新的runSequentially
。有关示例实现,请参见here。
如果要严格通过setState
管理队列,则完全不需要runSequentially
方法。 runParagraph
本身会(a)检查它是否已经在运行,并且(b)完成后从数组中取出下一个元素,然后再次调用runParagraph
直到没有剩余。