0

The following renderChat function is used to render a message and an image onto a chat board. Inside the function there is another function

var onComplete = function () {

which does all the work of creating the list element and appending it to the chat list. After the onComplete function, there is only this three lines of code

  img.onload = onComplete;
  img.onerror = onComplete;
  img.src = c.chat.value.media;

Because the var onComplete is a function assigned to a variable, I assumed it had to be called with parenthesis. Thus, when I see this

img.onload = onComplete;

I understand that the function has been assigned to a new variable, but has never been called. Yet, when I use the application, the chat has been rendered by the time we reach img.src = c.chat.value.media;

Can you please explain how my understanding of JavaScript is mistaken and how this function is working?

 var renderChat = function (c) {
    debug("Rendering chat: key='%s' fingerprint='%s' message='%s' created='%s' imageMd5='%s'",
      c.chat.key,
      c.chat.value.fingerprint,
      c.chat.value.message,
      c.chat.value.created,
      md5(c.chat.value.media));
    var renderFP = c.chat.value.fingerprint;

    if (!isMuted(renderFP)) {
      var img = new Image();
      var onComplete = function () {
        // Don't want duplicates and don't want muted messages
        if (body.find('li[data-key="' + c.chat.key + '"]').length === 0 &&
            !isMuted(renderFP)) {

          var li = document.createElement('li');
          li.dataset.action = 'chat-message';
          li.dataset.key = c.chat.key;
          li.dataset.fingerprint = renderFP;
          li.appendChild(img);

          // This is likely your own fingerprint so you don't mute yourself. Unless you're weird.
          if (userId.val() !== renderFP) {
            updateNotificationCount();

            var btn = document.createElement('button');
            btn.textContent = 'mute';
            btn.className = 'mute';
            li.appendChild(btn);
          }

          var message = document.createElement('p');
          message.textContent = c.chat.value.message;
          message.innerHTML = transform(message.innerHTML);
          li.appendChild(message);

          var createdDate = moment(new Date(c.chat.value.created));
          var timestamp = document.createElement('time');
          timestamp.setAttribute('datetime', createdDate.toISOString());
          timestamp.textContent = createdDate.format('LT');
          timestamp.className = 'timestamp';
          li.appendChild(timestamp);

          var size = addChat.is(":visible") ? addChat[0].getBoundingClientRect().bottom : $(window).innerHeight();
          var last = chatList[0].lastChild;
          var bottom = last ? last.getBoundingClientRect().bottom : 0;
          var follow = bottom < size + 50;

          chatList.append(li);
          setupWaypoints(li);
          debug('Appended chat %s', c.chat.key);

          // if scrolled to bottom of window then scroll the new thing into view
          // otherwise, you are reading the history... allow user to scroll up.
          if (follow) {
            var children = chatList.children();
            if (children.length > CHAT_LIMIT) {
              children.first().remove().waypoint('destroy');
            }

            li.scrollIntoView();
          }
        }
      };

      img.onload = onComplete;
      img.onerror = onComplete;
      img.src = c.chat.value.media;
    }
  };
2
  • The function is called, but not explicitly. It's called whenever the image loads. Commented Jan 5, 2014 at 22:01
  • In img.onload = onComplete; you assign a function object to the onload event. So the function executes at some point, when the image is loaded. If you execute the function right away, you assign the returned value of the function to the event, that expects a function to be called. Commented Jan 5, 2014 at 22:02

3 Answers 3

1

The HTMLImageElement object will cause functions assigned to its onload and onerror properties to be called at the appropriate times (i.e. when the HTTP response is received or the wait for it times out).

The code to do this is built into the browser. The properties (or the addEventListener function in more modern code) are the only ways with which you can interact with that code.

Sign up to request clarification or add additional context in comments.

Comments

1

In Javascript you can store functions in variables, this is what you did with onComplete(). The img object will execute a function(so called callback) after successfully loading the image (onload) or if it could not load the image(onerror).

To tell the img object which method to call after those events, you need to give it the method name like this without parenthesis:

  img.onload = onComplete;
  img.onerror = onComplete;

If you would use parenthesis the function would be executed immediately and img.onload wouldn't contain a reference to a function but the result of onCompleted.

Comments

0

img.onload = onComplete; will assign the function onComplete to the onload handler. THis means, that the function is called, when the vent happens.

img.onload = onComplete(); will assign the result of calling the function onComplete to the onload handler. This means, that the function is called immediately, is expected to return another function (or a string containing valid JS), which in turn will be called when the event happens.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.