This tiny Javascript program returns the sha256 hash of its text.
const shasum = require('crypto').createHash('sha256'); const stream = require('fs').createReadStream(__filename); stream.on('error', function() { console.log('Error.'); }); stream.on('data', function (chunk) { shasum.update(chunk); }); /* <--- data line */ stream.on('end', function() { const sha = shasum.digest('base64'); console.log(`The sha is ${sha}`); });
Executed with Nodejs Erbium, it works as expected.
However, after writing it I thought that the function expression was not needed and so I changed the data line
with the following:
stream.on('data', shasum.update);
And it crashes with a horrific error message:
if (state[kFinalized]) ^ TypeError: Cannot read property 'Symbol(kFinalized)' of undefined at ReadStream.update (internal/crypto/hash.js:78:12) at ReadStream.emit (events.js:311:20) at addChunk (_stream_readable.js:294:12) at readableAddChunk (_stream_readable.js:275:11) at ReadStream.Readable.push (_stream_readable.js:209:10) at internal/fs/streams.js:210:12 at FSReqCallback.wrapper [as oncomplete] (fs.js:487:5)
Javascript is very flexible with function calls, but according to the documentation the stream.on data
call should pass only one parameter.
Why is the behavior different?
Advertisement
Answer
The issue is the context.
The stream will bind the data
function to the stream itself
stream.on('data', function (chunk) { console.log(this) // it is the `stream` shasum.update(chunk) })
In this case, the shasum.update
is bind to the stream, so the update function will not work:
function update(data, encoding) { const state = this[kState]; if (state[kFinalized]) throw new ERR_CRYPTO_HASH_FINALIZED();
To let it works you must write this statement:
stream.on('data', shasum.update.bind(shasum))