origamitower / folktale

[not actively maintained!] A standard library for functional programming in JavaScript
https://folktale.origamitower.com/
MIT License
2.05k stars 102 forks source link

Restoring a cancelled Task #224

Closed cdoublev closed 5 years ago

cdoublev commented 5 years ago

My "issue" is a question.

I use Task to implement an animation library with an animate function as interface, which executes at each render frame, a function it has received as argument, until this function signals its end to animate, which resolves the task execution.

This library also handles mapping and chaining animations, but I struggle to implement a togglePlay interface, because I can't find a way to "restore" the full previous animation task computation(s), when resuming the animation which was paused with togglePlay. I can resume the last animation that was cancelled, but if the user has chained multiple animations, I can't find a way to execute them also.

(Future) swap() doesn't update a cancellation state. orElse() only works with rejected tasks. Some promise cancellation proposals are demonstrating cancelled promises which can be chained with catch, or a third form which handles success, error, and cancellation.

I'm not sure of the assumptions that can be made concerning a cancelled task. I'm not claiming that Folktale should consider it as a rejected task, or that a cancelled state should be swapable. But I'm available to PR something for this if required.

Steps to reproduce

NA

Expected behaviour

NA

Observed behaviour

NA

Environment

(Describe the environment where the problem happens. This usually includes:

Additional information

N/A

robotlolita commented 5 years ago

Mmh, I'm not sure if I understood the use case correctly. Do you cancel a Task at some point A, and then at some point A + 1 you'd like to resume it from where it was left? It seems like it would be better to handle your use case with a running state in the animation than rely on Task for it.

In any case, Tasks are supposed to represent a complete process (which will usually be asynchronous). They define how to create resources for the process, how to execute the process, and how to free the resources created by the process—which allows you to just call task.run() many times, and have perfect copies of the original process be spawned. This is also one of the reasons why continuing from where you left after cancellation isn't really possible. If you cancel a task, all resources associated with it will be free'd.

That said, tasks do support reacting to cancellation. See Task#willMatchWith (https://folktale.origamitower.com/api/v2.3.0/en/folktale.concurrency.task._task.willmatchwith.html) and TaskExecution#listen (https://folktale.origamitower.com/api/v2.3.0/en/-unknown-module-.folktale.concurrency.task._taskexecution.prototype.listen.html)

If you can provide an example of what you're trying to do I might be able to give you a better answer :x

cdoublev commented 5 years ago

Yes, you understood me perfectly. I will just add the following pseudo-example to better explain what I didn't succeed to achieve yet:

  const execution = 
    animate(runAnimation1)  // Duration: 1s
      .chain(runAnimation2) // Duration: 1s
      .chain(runAnimation3)
      .run()

  setTimeout(() => execution.cancel(), 1200)

  // How to resume runAnimation2 by starting at 200 ms? (it's ok, I got a solution)
  // Then continue w/ runAnimation3 (-> couldn't achieve that yet)

Your answer makes it clear: I can't continue from where I left after cancellation. And I was wrong to think it would using cancellable promise, sorry. So I close this issue.

I think I can record a custom execution state containing each animation function given to animate() / chain(), associated to a "done" flag when required, and then resume a cancelled sequence by rewiring the animation functions which are not "done".

I think I just needed to leave this issue for a few days. But thank you again for your help. :)