frosty frosty - 7 months ago 20
Javascript Question

Return resolved deferred from another function

I'm animating an automated conversation with a bot.

When the first message ("Hi there, take a look at this!") has been printed, I want to go to the next function

.then()
. However I don't know how to set up the
r.resolve()
in this case, it's like nested or something.

var messages = [
"Hi there, take a look at this!",
"Enter your address",
"blah blah"
];

function printLetters(target, message, index, interval, n) {

r = $.Deferred();
$('#m'+n).fadeIn();

if (index < message.length) {
$(target).append(message[index++]);
setTimeout(function () {
printLetters(target, message, index, interval, n);
}, interval);
} else {
r.resolve();
}
elem.scrollTop = elem.scrollHeight;

return r;

}

function printMessage(n) {
r = $.Deferred();
setTimeout(function(){
$('#m'+n+'>p').empty();
r = printLetters('#m'+n+'>p', messages[n-1], 0, 40, n);
}, 400);
return r;
}

function startConversation() {
printMessage(1)
.then(showThumb1AndTapButton)
.then(showThumb2AndScroll)
.then(choosePaymentMethod)
.then(enterAddress);
}

startConversation();


In this case, I want to get from
printMessage(1)
to the next
.then()
function, but I'm not sure how.

I'm not sure how to return the resolved
r
if the message has finished printing from the other function?

Answer

Firstly, define your variables, use var in the needed scope for each variable.

The problem is how you're handling the r variable. You're creating the deferred and storing it on r, returning r and then, 400ms after the function ended, creating a new r (because the previous r haven't been defined with var, this one is other variable in the timeout's handler function) with the output of printLetters which is other deferred... that last r has nothing to do with the value returned by printMessage.

I would suggest you to define your r (or other name more descriptive) as global (outside any function), create the deferred object just once and then work always with this variable.

Update

Since you have several functions that need to return a deferred, you could just pass the deferred as an argument. The point is to be consistent with the variables. For example (not tested, take the suggestiong and try it yourself):

function printMessage(n) {
    var r = $.Deferred();
    setTimeout(function(){
        $('#m'+n+'>p').empty();
        printLetters(r, '#m'+n+'>p', messages[n-1], 0, 40, n); <--var needed for this r to be defined inside here
    }, 400);
    return r;
}

And then

function printLetters(r, target, message, index, interval, n) {
    ...
    ...
    r.resolve(); <--Note this is the parameter r
}

No need to return anything or creating a second deferred, you're working with the same object created and returned by printMessage.