Ollie Jones Ollie Jones - 3 months ago 19
Javascript Question

chrome.webstore.install calling both callbacks? Why?

I'm trying to inline-load a Google Chrome extension using the

function.

Here's the link from within my page's
<head>
stanza.

<link rel="chrome-webstore-item"
href="https://chrome.google.com/webstore/detail/oafp--redacted--ffencd" />


Here's the button.

<input type="button" class="btn btn-default" onclick="getExtension();">Go</input>


Here's the Javascript, which appears right before the closing
</body>
tag.

<script type="text/javascript">

function getExtension() {

function extensionFailed(reason) {
console.log("extension Install Failed:", reason);
}

function extensionInstalled() {
console.log("installed");
};

console.log("calling install");
chrome.webstore.install(undefined, extensionInstalled(), extensionFailed());
console.log("install returned");

};

</script>


Clicking the button that calls getExtension gets me this sequence of events, delivered one after the other immediately.


  1. "calling install" (right before call to
    chrome.webstore.install()
    )

  2. "installed" (in success callback)

  3. "extension Install failed, undefined" (in failure callback)

  4. "install returned." (after return from call to
    chrome.webstore.install()
    )



Somewhere in the middle of that, asynchronously, I get the inline installation popup and accept it.

I thought...


  1. the failure callback should only get called on failure.

  2. the failure reason should be something meaningful, not
    undefined
    .

  3. the success callback should be deferred until the user accepts the installation.



I must be doing something wrong. ...

Answer

Answer:

In this line of code:

chrome.webstore.install(undefined, extensionInstalled(), extensionFailed());

You're actually executing the functions by having the () in extensionInstalled() and extensionFailed(). If you want to pass them in as callbacks, you can actually pass in the functions themselves as you would a var:

chrome.webstore.install(undefined, extensionInstalled, extensionFailed);


Functions as variables:

Note: This does not apply to your code because you define your functions before you call them, which is good practice.

You can also define variables as functions, which IMO only makes things more confusing. Take for example, these 2 function definitions:

var myfunctionVar = function() {
    console.log('hello, world');
}

function myfunction() {
    console.log('hello, world');
}

You would call these functions in a normal way (i.e. myfunctionVar() and myfunction()).

The key difference between these 2 definitions is that myfunctionVar will only become available once the definition itself is executed whereas myfunction is immediately available in the scope of the parent function that defines it (or once your script file is executed if there is no parent function). This is due to "hoisting", which only makes things more complicated.

In this example, you would not be able to call myfunctionVar() before you assign it. However, this would not be the case for calling myfunction(), and you can call it anywhere in the parent function.

See this answer for a more information.

Functions are a bit more complicated (and powerful!) in Javascript than in other languages, so hopefully this answer clears a few things up for you. You can read about hoisting from W3Schools, here.