Jason C
Jason C

Reputation: 40436

Chaining functions that return deferred objects

I have some functions that return jQuery Deferred objects and I'm having trouble getting my head around chaining them and processing the results.

Consider the following example:

const start = Date.now();

// Print a message with a timestamp.
function log (v) {
    console.log(`${Date.now() - start} ${v}`);
}

// Return a deferred function that resolves 1 second later with 'value'.
function test (value) {
    log(`test(${value})`);
    return $.Deferred(function (def) {
        window.setTimeout(function () {
            log(`resolve(${value})`);
            def.resolve(value);
        }, 1000);
    });
}

// Example:
test(42)
    .then(function (v) { log(v); })
    .then(test(99))
    .then(function (v) { log(v); })
    .then(function () { log('done'); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

This is supposed to run test(42), then do something with its results, then run test(99) then do something with those results, all in order. However, it actually outputs (first number is ms since program started):

0 test(42)
0 test(99)
1003 resolve(42)
1003 42
1003 undefined    <-- supposed to be 99
1005 done
1005 resolve(99)

So both of the tests get called at the same time right at the start, and everything else is off. What I want it to output is something like:

0 test(42)
1000 resolve(42)
1000 42
1000 test(99)
2000 resolve(99)
2000 99
2000 done

How can I make this work? I tried returning $.Deferred(...).promise(), with no change in behavior, and I also tried using done instead of then but the only change was it printed 42 a second time instead of undefined.

Upvotes: 2

Views: 43

Answers (1)

Taplar
Taplar

Reputation: 24965

Each deferred only resolves once. For each deferred chain, you have to attach them correctly. Also the second call to test needs to be in a function so that it does not execute immediately.

const start = Date.now();

// Print a message with a timestamp.
function log (v) {
    console.log(`${Date.now() - start} ${v}`);
}

// Return a deferred function that resolves 1 second later with 'value'.
function test (value) {
    log(`test(${value})`);
    return $.Deferred(function (def) {
        window.setTimeout(function () {
            log(`resolve(${value})`);
            def.resolve(value);
        }, 1000);
    });
}

// Example:
test(42)
    .then(function (v) { log(v); })
    .then(function () {
        test(99)
           .then(function (v) { log(v); })
           .then(function () { log('done'); });
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Upvotes: 1

Related Questions