1

I have a question regarding JavaScript functions.

As an example, please refer to the below code.

  • In the first 2 lines, I open an indexedDB.
  • After that, I attach the onsuccess function to the openRequest.
  • The alert comes up correctly.

I am assuming that the 'open' function triggers the 'success' event function. But how can this work, since the 'success' function is attached to the openRequest after the 'open' function is called?

var indexedDB = window.indexedDB;
var openRequest = indexedDB.open('MyTestDB');
openRequest.onsuccess = function (response) {
    alert('sucess');
};
aychedee
  • 24,871
  • 8
  • 79
  • 83
Joseph Caruana
  • 2,241
  • 3
  • 31
  • 48
  • It's because of something called 'hoisting' (look it up) that the location of the definition for your callback does not matter. functions are "moved" to the top. Consequently, it does not matter where in the current scope you declare the function, it can be called from anywhere. – MJB Nov 02 '13 at 12:03
  • 1
    @DatProgram I don't think that hoisting applies here because the OP uses an anonymous function. – ComFreek Nov 02 '13 at 12:11
  • @ComFreek: well if I write "var func = function(response){..}" and then "openRequest.onsuccess = func" I get the same result, but func is obviously not anonymous? I mean, the name of the function IS "onsuccess", isn't it?! – MJB Nov 02 '13 at 16:42
  • 2
    @DatProgram `function(){}` as an expression is an anonymous function. `onsuccess` is a property of an object. It is assigned a function. Compare [my first fiddle](http://jsfiddle.net/E9qJU/) and [my second fiddle](http://jsfiddle.net/K92Fw/). The second fiddle doesn't work. [This link](http://stackoverflow.com/questions/1013385/what-is-the-difference-between-a-function-expression-vs-declaration-in-javascrip) might help you understanding the difference. – ComFreek Nov 02 '13 at 16:59
  • yeah thanks a lot!! It's crazy that you use something everyday but still have a missconception about it. should I delete my comment? – MJB Nov 03 '13 at 05:10

3 Answers3

5

The call to indexDB.open is asynchronous. It returns immediately and the rest of the code continues to run. When the db is actually opened an event is triggered. This event is placed in the event queue. The JavaScript interpreter checks the event queue periodically. But the interpreter is also single threaded. It doesn't jump out of the current code it is executing to check it. The onsuccess function will never be called before it is defined. In fact the DB itself is never be opened until later as well.

For example, if you put an endless while loop at the end of your code the onsucess function would never be run.

var indexedDB = window.indexedDB;
var openRequest = indexedDB.open('MyTestDB');
openRequest.onsuccess = function (response) {
    alert('sucess');
};

while (true) {};

Execution would be blocked at that point and the interpreter would never check the event queue and never run the on success function.

http://javascript.info/tutorial/events-and-timing-depth

aychedee
  • 24,871
  • 8
  • 79
  • 83
2

That is possible because the JavaScript VM (take V8 for example) executes the assignment of the success handler faster than it opens the indexDB. This is caused by the fact that the call to indexedDB.open() is asynchronous, therefore the VM opens the DB in the background and executes the event handler assignment.

If you delay the assignment of the event handler, you will see that it won't get called anymore:

→ jsFiddle

var indexedDB = window.indexedDB;
var openRequest = indexedDB.open('MyTestDB');

window.setTimeout(function () {
    openRequest.onsuccess = function (response) {
        alert('sucess');
    };
}, 1); // also test higher values - 1ms worked fine for me

Also read aychedee's answer above!

Community
  • 1
  • 1
ComFreek
  • 29,044
  • 18
  • 104
  • 156
  • was JUST gonna type that +1 – krishwader Nov 02 '13 at 11:07
  • It's not that the interpreter executes the assignment faster... it is that it executes it before it executes the event. There isn't a race condition. What a crazy world that would be. – aychedee Nov 02 '13 at 11:44
  • 1
    Also, your code example actually still pops up the alert. Because setTimeout with that short a timeout gets put on the event queue immediately. Try 2000 milliseconds to actually put it on the event queue behind the indexdb open. But then you really would have a race condition. – aychedee Nov 02 '13 at 12:02
  • @aychedee 1 ms worked fine for me. I update my answer. +1 for yours, nice explanation. – ComFreek Nov 02 '13 at 12:06
  • You must have a quick machine! My laptop has an event loop resolution of 4ms. i.e it runs 1000 calls to `setTimeout(function () {}, 0)` in about 4 seconds. http://jsfiddle.net/VeheG/ – aychedee Nov 02 '13 at 14:15
  • @aychedee I get 3,98 in IE 11 and 5,74 in Chrome 30. Actually, I see the alerts() sometimes in IE, but never in Chrome. (I also edited your fiddle to run 10.000 iterations instead of only 1000,) – ComFreek Nov 02 '13 at 14:22
  • 1
    Interesting that IE11 is a bit faster. I can honestly say that I have never even seen IE10 or 11 running. I should check them out one day :) – aychedee Nov 02 '13 at 14:34
0

indexedDB.open makes an asynchronous request in the background. When it is ready the onsuccess event listener gets called.

It would be a better practice to set the event handler before indexedDB.open.

adambene
  • 1,143
  • 9
  • 16