You haven't given enough information about the environment, the planned game design, and your current engine structure to suggest anything specific, so here's the general advice:
There is no one optimal solution. Get something drawing and then use that until it starts to break, then iterate; it's a very game-design related problem, and game design is predicated on iteration, so bringing the iteration down to the engine level(rather than to fret and try to come up with a "perfect solution" out of the gate) ends up being the best way to explore this aspect of gameplay. Some examples of how much your solution may vary:
If you have an anim predicated on just looping through the frames while the "player entity" is in some state(e.g. walk, jump, idle), then you keep a frame counter, increment it with the game's timestep, and draw frames according to the counter.
If you have an anim that needs a lot of contextual information to display properly, like turning towards different facings, grabbing on to ledges, etc., then you add additional state checks along with the frame counter, and if there are enough forms of state you may want to formalize it as a finite state machine run every frame. You might also have some kind of procedural effect tied to entity state: rotation, blink, scaling, shaders...
If anims trigger gameplay events(like throwing a punch) you'll have to decide whether to put that information directly in the animation code or to introduce a data-driven mechanism for "fire this event now, spawn this object, turn on this collision volume..."
Then there are details like origin points, image size(size may change over time for some anims), variable playback speeds....
Like I said up front, don't try for a perfect solution. It just depends on what the game needs.