addresses #1
use hash.copy to copy hash object before update and digest, making it reusable. Every JS runtime I looked at, that supports hash.digest and hash.update, also support hash.copy.
This holds a slight performance penalty, where doing 20 updates takes around 0.01ms longer. However the slowdown is just relative to the number of calls and not to the size of each string/hash object.
If you find this to be a problem, this could be mostly mitigated by collecting in a list per update chain and only calling copy in finish and when the pending collection reaches a certain size.