Search code examples
javascriptes6-promise

How to properly concatenate promises in different functions


I'm a newbie and trying to figure out something in Javascript that should be simple. I have 2 functions let's say

function play1(){
  Promise.resolve()
    .then(() => put('A', 1000))
    .then(() => put('B', 1000))
}
function play2(){
  Promise.resolve()
    .then(() => put('C'), 1000)
    .then(() => put('D'), 1000)
}

I need a third function so that it executes sequentially A, B, C, D What I've tried so far with no luck:

function playAllSequentially(){
  
  Promise.resolve()
    .then(() => play1())
    .then(() => play2())
}

but this doesn't get the job done, of course I could do

Promise.resolve()
    .then(() => put('A', 1000))
    .then(() => put('B', 1000))
    .then(() => put('C', 1000))
    .then(() => put('D', 1000))

but that is not the idea

in case it matters the content of put() is

function put(text, duration){
    $('#txtRemarks').text(text);
    delay(duration);
}

Thanks in advance


Solution

  • It sounds like delay returns a promise it fulfills after a period of time. But put is completely ignores that promise, so it doesn't wait. Similarly, play1 and play2 don't return anything, so there's no reason for whatever is calling them to wait either. You need to return the promise chain. (Separately, you have the closing ) in the wrong place in the calls to put in play2.)

    See the marked changes (but keep reading):

    function play1() {
        return Promise.resolve() // <=== return
            .then(() => put("A", 1000))
            .then(() => put("B", 1000));
    }
    function play2() {
        return Promise.resolve() // <=== return
            .then(() => put("C", 1000))  // <=== parens
            .then(() => put("D", 1000)); // <=== parens
    }
    
    function playAllSequentially() {
        return Promise.resolve() // <=== return
            .then(() => play1())
            .then(() => play2());
    }
    
    function put(text, duration){
        $('#txtRemarks').text(text);
        return delay(duration); // <=== return
    }
    
    playAllSequentially();
    
    function delay(duration) {
        return new Promise((resolve) => {
            setTimeout(resolve, duration);
        });
    }
    <div id="txtRemarks"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    But, that code has the explict promise creation anti-pattern. You don't need those Promise.resolve() calls if put, play1, and play2 return promises:

    function play1() {
        return put("A", 1000)
            .then(() => put("B", 1000));
    }
    function play2() {
        put("C", 1000)
            .then(() => put("D", 1000));
    }
    
    function playAllSequentially() {
        return play1()
            .then(() => play2());
    }
    
    function put(text, duration){
        $('#txtRemarks').text(text);
        return delay(duration); // <===
    }
    
    playAllSequentially();
    
    function delay(duration) {
        return new Promise((resolve) => {
            setTimeout(resolve, duration);
        });
    }
    <div id="txtRemarks"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    But, here in 2022, that's not how I'd write this code. Instead, I'd use async functions:

    async function play1() {
        await put("A", 1000);
        await put("B", 1000);   // Maybe a return here, if you want play1
                                // to return the result of `put`
    }
    async function play2() {
        await put("C", 1000);
        await put("D", 1000);   // See above
    }
    
    async function playAllSequentially() {
        await play1();
        await play2();          // See above
    }
    
    async function put(text, duration){
        $('#txtRemarks').text(text);
        await delay(duration);
    }
    
    playAllSequentially();
    
    function delay(duration) {
        return new Promise((resolve) => {
            setTimeout(resolve, duration);
        });
    }
    <div id="txtRemarks"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


    Finally, in all of the above the functions never reject their promises, but real world functions usually can, so playAllSequentially (or whatever calls it) should handle rejection.