2

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?

2
  • 1
    Does this answer your question? How to access the correct `this` inside a callback? Commented Aug 6, 2020 at 6:36
  • 1
    Basically if you just want to use a function reference, you need shasum.update.bind(shasum). However, I personally don't like it - it looks odd to have a "sandwich" of the context. If you want it shorter, just use an arrow function chunk => shasum.update(chunk) Commented Aug 6, 2020 at 6:38

1 Answer 1

1

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))
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.