2

The asynchronous function I am trying to call is defined by onClick property of DomOutline. For this example, domClickHandler is like callback that receives the selected element.

    var iWantThis;

    var myDomOutline = DomOutline({
        onClick: domClickHandler,
        filter: false,
        stopOnClick: true,
        hideLabel: true
    });

    var domClickHandler = function(element){
        iWantThis = element
        console.log("I am the element you've selected: " + element);
    };

    myDomOutline.start();
    console.log("From the outside world: " + iWantThis);
    return iWantThis;

DomOutline.start() returns right away and domClickHandler is asynchronous callback. So in this example, the last console.log will return undefined even before I select the element. I have tried trying $.when() on a function that wraps around DomOutline.start() to return promise(), but it didn't make the async call synchronous. What is the way to use promise here so that I could return the DOM object when it has been selected?

I promisified the callback, but I am not sure how this will help me to achieve synchronous return of the array iWantThis

var domClikcHandler= function(element){
        var dfd = $.Deferred();
        classifiedElements = __classifyChildrenElements(element);
        dfd.resolve(classifiedElements);
        dfd.then(function(e){
            console.log(e);
            iWanThis = e;
        });
        return dfd.promise()
    };
Forethinker
  • 3,548
  • 4
  • 27
  • 48
  • You are expecting promises to do something that they do not. A promise is an abstraction of a value, not something that converts an asynchronous process to synchronous. You probably want to [convert your existing callback api to promises](http://stackoverflow.com/questions/22519784/how-do-i-convert-an-existing-callback-api-to-promises). Once achieved, DomOutline's `onClick` callback will feed a promise, and you can pass a callback to promise method `.then()`. – Roamer-1888 Dec 25 '14 at 03:49
  • @Roamer-1888 I can convert the callback `domClickHandler` to return a promise, but your last sentence is not clear to me. Where would I put the chaining of of `.then()`? – Forethinker Dec 25 '14 at 04:21
  • Read the linked Q/A. – Roamer-1888 Dec 25 '14 at 04:22
  • @Roamer-1888 I have updated the question to add the changes, but I am still not clear how I can return the array within the callback. Other than going into some client-server model, is there a way for me to achieve this. If promise is not the right direction, could you refer me another approach? – Forethinker Dec 25 '14 at 04:34
  • Forethinker, you're still missing the point - you can't handle asynchronous processes synchronously. Whether you use promises or not, the response of an asynchronous process must be handled in a callback. With promises, the only thing that changes is the object to which that callback is passed. – Roamer-1888 Dec 25 '14 at 04:53
  • Besides, an onClick handler isn't a candidate for promisification, as it will get called many times and a promise can only ever be resolved/rejected once. Your only realistic option is to do whatever is necessary with `element` inside the callback. Don't try to address it in the "outside world". – Roamer-1888 Dec 25 '14 at 05:37
  • @Roamer-1888 well, with the exception of generators. – Benjamin Gruenbaum Dec 25 '14 at 07:37
  • Thank you for the reminder @BenjaminGruenbaum. For Forethinker's benefit, "generators" are something that will be introduced into Ecmascript (javascript) at some later edition. – Roamer-1888 Dec 25 '14 at 09:57

1 Answers1

2

Let's take this one step at a time.

What a promise is

A promise an abstraction over the notion of value - it represents a value + time. Operations you perform on it queue and will happen when the time comes.

A promise starts off as pending and then goes through resolution to become either:

  • fulfilled - meaning it is available for use and chaining.
  • rejected - meaning that the operation failed and you can attempt to recover from it

In libraries that are not jQuery and in native promises - the transition process as well as the execution of handlers is always asynchronous. This is in order to prevent race conditions in cases it might be asynchronous.

What a promise is not

A promise is not an event emitter - you cannot bind a promise to an event that happens more than once since it represents a single value. The dual of promises that represents multiple values is called an Observable. You cannot bind a promise to a click event.

A promise is not magic - it is usually implemented in JavaScript, it cannot convert asynchronous code to synchronous code, while its then abstracts the notion of sequencing itself - it cannot without language support 'stop' code on asynchronous operation in order for that other language facilities are required like generators (ES6) or async/await (ES7). For most browser users who don't want to go through a compile step promises can make your life easier but not make asynchronous code synchronous.

In general promises use return values and thrown exceptions for well... return values and thrown exceptions. A promise resolves once with a single value just like a value has just one value and once you have obtained it it does not change.

How to use promises

In you case the click handler fundamentally can't be modeled with promises - it requires an event emitter aka observable. What you have with the onBtnClick looks just fine.

In the case of the ready event - assuming you promisified it correctly (calling $.when doesn't help on its own) you need to chain to it:

 myDomOutline.start().then(function(){
     alert("Ready!");
 });

If you want to access it from the outside that's just fine since promises compose:

function startWithData(){
     var request = $.ajax(...);
     return myDomOutline.start().then(function(){ // note the return
         startAnimations();
         doAnotherThing();
         return request; // return the request
     });
}

startWithData().then(function(data){
    // ajax done and ready event fired
    // access data here
});

As additional reading please see How to return the response from an AJAX call? which is not promise centric but still very relevant.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504