0

I was working with q library for a short period of time, and had success with processing data that I get from ajax in sequential manner.

By sequential processing of data I mean that after each of ajax call, I do a set of .then( function(){} ) and continue onto the next ajax call ...

As part of processing a single data entry (ajax data) I have to output result of ajax on screen. I have a deferred object that I resolve after I enter text from ajax data into a div - I am notifying ( with Q's progressHandler ) that I am done with entering text into a div (100% of text was entered into a div).

Everything works as expected in q's v. 0.9.6. But with v. 0.9.7 for some reason I get a TypeError {} :s Apparently the deferred object does not propagate the progress and fails for some reason. The changelog did not help me much: q changelog.

I have prepared 2 versions of code, simplified it as much as I can. Here is version that works - 0.9.6 and the one that does not work - 0.9.7. Both examples have same code, the only difference is the version of q library.

I have an explanation of the code in the CSS section. I hope that I am being as clear as possible there.

I apologize in advance if this is some stupid question.


And since I can't just post JSFiddle links, here is the code:

Libraries that I use:

  • jQuery
  • ajaxFake by ANas Nakawa
  • Teletype (me - for typing text into a div)
  • yodaProgress (me - a graphical progress bar. Has .progress(step 0.00 - 1.00) and .isDone() functions)
  • q v. 0.9.6 / q v. 0.9.7

Html:

<div id="progress_1"></div>

Javascript:

$(document).ready(function() {

    // For DEFERRED object (referencing in 2.2.1)
    var mainObject = {
    }

    // For fake ajax Data
    $.ajax.fake.registerWebservice('blah', function (data) {
        return {
            result: 'My fake ajax result should be typed into the div!', 
        };
    });

    // 1. START
    var nextTick = Q.when();

    // 2. PROCESS 3 ITEMS SEQUENTIALLY
    for (var i = 0, length = 3; i < length; i ++) {
        nextTick = nextTick.then(
            processAjaxCall,
            function(error)     { console.log("This is an error 2.");   },
            function(progress)  { console.log("This is a progress 2."); }
        );

    }

    // 3. FINALLY DO THIS
    nextTick.fin(
        function(result)    { console.log("This is a final result 3.");     },
        function(error)     { console.log("This is an error 3.");   },
        function(progress)  { console.log("This is a progress 3.");}
    );


    // 2.0   ONE OF 3 SEQUENTIALL ITEMS
    function processAjaxCall () {

        var fakeResult;

        // 2.1.   AN AJAX DATA
        var promise = Q.when(
            fakeAjax()
        );

        // 2.2.   SETTING OF TEXT (from 2.1.) INTO DIV
        var promiseToDo = promise.then(
            function (result) {
                console.log("Result of ajax call:", result);
                return setText(result);
            },
            function (error)    { console.log("Ajax call error 2.2:", error);       },
            function (progress) { console.log("Ajax call progress 2.2:", progress); }
        );

        // 2.3. SETTING OF PROGRESS (100% - color green for a DIV)
        return promiseToDo.then(
            function (result) {
                console.log("Text was set 2.3");
            }, 
            function (error) {
                console.log("Error 2.3:", error);
            }, 
            function (progress) {

                var promiseElement = new YodaProgress(

                    $("#progress_1")

                    ,{
                        doneCSSRule: {
                            'background-color': "#00CC00"
                        }
                    }
                );

                promiseElement.progress(parseFloat(progress).toFixed(2));

                if (promiseElement.isDone()) {
                    mainObject.deferred.resolve();
                }

                //console.log("2.3 Progress %:", progress);
            }
        );

    }


    // 2.1.1 - a fake Ajax Data
    // Anas Nakawa
    // https://github.com/anasnakawa/jquery.ajax.fake
    function fakeAjax () {
        return $.ajax({
            type:'GET',
            dataType:'jsonp',
            fake: true,
            url:'blah'
        });
    }

    // 2.2.1 - setting text into a DIV
    function setText (result) {

        console.log('Passing in result:', result);
        console.log('About to set text to:', result.result);

        mainObject.deferred = Q.defer();
        promise = mainObject.deferred.promise.when(

            // Teletype is a library to type text into a DOM element
            // as if human was typing, sorta
            Teletype(
                document.getElementById("progress_1"), 
                result.result, 
                40, 
                true, 
                function (i, l) {

                    mainObject.deferred.notify(
                        parseFloat((i+1)/l).toFixed(2)
                    );
                }
            )
            //,function(error)      { console.log("This is an error 2.2.1", error);       }
            //,function(progress)   { console.log("This is a progress 2.2.1", progress);}
        );
        console.log("RETURNING PROMISE");
        return promise;
    }


});

Explanation:

  If it is v. 0.9.7 I GET a "TypeError {}" and div is typed in differently
  If it is v. 0.9.6 it works as expected.

  Code Explanation:

  Forget the ugliness and everything.
  This code is modified for illustrative purposes.

  What this code does is basically this:

  - Process 3 sequential function calls

    - these calls turns out to consist of:

      - an ajax Call
      - setting div #progress_1 TEXT with ajaxCall response
      - on progress of setting text into a #progress_1 div make DIV green.
 */

P.S. When I load page and open a console in Chrome later, I get a TypeError object that I can inspect and it says "Object has no 'when()' method." That gave me the clue where to start. Before that if console was open in Chrome before I load the page it would just show 'TypeError {}' message. Have to research more on why such vast difference in operation.

Thanks a lot!

Plyto
  • 741
  • 1
  • 9
  • 18

1 Answers1

0

Ok, I have solved the problem :p

Apparently the structure of deferred object was changed internally with 0.9.7 release. Weird enough changelog file shows information on the changes under "0.9.6" section.

When I check the console in 0.9.6 for

var deferred = Q.defer();
deferred.promise.__proto__ 

I can see that when() function is there. And deferred.promise is not an actual Promise object, but something different?.

However when I check same in version 0.9.7 for

var deferred = Q.defer();
deferred.promise.__proto__ 

I get back the Promise object that has then() method and 'when()` method no longer exists.

So yea, changelog was misleading or maybe I am losing my mind.

If I go to GitHub q library's repo, and select "Tags" -> "0.9.6" -> "CHANGES.md" file, the topmost portion of file shows "0.9.5" section. So I assume author tried to convey that these are the changes FROM 0.9.5 that are in 0.9.6.

Maybe it makes sense, because master branch lists changes under 0.9.7, so they are again, changes FROM 0.9.7 to the next version (I assume 0.9.8).

Now I know better to not trust the numbers in a changelog! :p

Thanks everyone who participated!

Plyto
  • 741
  • 1
  • 9
  • 18