Как я могу выполнять обещания в последовательности и динамически - PullRequest
0 голосов
/ 28 декабря 2018

В моем веб-приложении я могу запускать блоки кода (он создает обещание и ожидает выхода результата).Каждый раз, когда пользователь запускает абзац, я добавляю его идентификатор в массив и запускаю его последовательно.

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), но если мы выполним другой абзац до того, как первый закончится, это будет повторять одно и то же обещание дважды.

Как бы вы справились с этой динамикойочередь обещаний?Может ли рекурсивность работать в этом случае?

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

если мы запустим еще один абзац до того, как закончится первый, это будет повторять одно и то же обещание дважды.

Вам нужно будет сохранить очередь promise как свойство в вашемсостояние, вместо создания нового Promise.resolve() каждый раз, когда вы звоните runSequentially.См. здесь для примера реализации.

Если вы хотите управлять своей очередью строго через setState, вам вообще не нужен метод runSequentially.runParagraph сам по себе а) проверит, запущен ли он уже, и б) по окончании вычеркнет следующий элемент из массива и вызовет runParagraph снова, пока не останется ни одного.

0 голосов
/ 28 декабря 2018

Вам следует инициализировать другое свойство (возможно, 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, потому что обещаниесамо по себе не влияет на ваш рендер, так что это безопасно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...