Rob Cha
Rob Cha

Reputation: 139

Promise not waiting on one another

So my understanding of promises lead me to believe that my other promises would run one after another in my then chain but I'm doing something wrong here.

The code I'm using currently is as follows

const mainPromise = () => Promise.resolve(
    console.log('spinner spinning...')
    ...spinner code.... //this is omitted code
);

const getData = () => Promise.resolve(
    someObj.getProducts('data.json')
);

const updateProduct = () => Promise.resolve(
    setTimeout(()=>{
        someObj.updateProductHTML()
    }, 0)
);

const updateDom = () => {
    setTimeout(()=>{
        someObj.updateDOM()
    }, 0)
};

and my promise chain

mainPromise()
    .then(getData)
    .then(updateProduct)
    .then(updateDom)
;

They seem to be initially running in order but the Ajax call I have in getProducts also has a for loop worker to build my array of objects and is finishing after all my .thens run.

I am attempting to at least have my data call and worker finish before updateProduct and updateDOM runs

--- UPDATE ---

ok so with the revised promises set up as such as per suggestions in the comments and Samanime's answer

 const mainPromise = () => Promise.resolve(
    console.log('spinner spinning...')
);

const getData = () => new Promise( resolve => {
    console.log('getData');
        someObj.getProducts('data.json');
        resolve();
    }
);

const updateProduct = () => new Promise( resolve =>{
   console.log('updateProduct');
   someObj.updateProductHTML();
   resolve();
});

//execute promise chain

mainPromise()
    .then(getData)
    .then(updateProduct)
    .then(page.updateDOM)
;

I updated the promises to not immediately resolve and am attempting to call resolve after I call my functions ( although I'm uneasy as to if resolve will be called before or after these functions ).

Unfortunately, I'm still getting the same behavior. I've added console logs to my functions as well as my promises and I'm getting this list back

   log.spinner spinning
   log.getData
   log.updateProduct
   log.A log from the function updateProduct calls
   log.48 product objects created (for loop worker in my getProducts   function)
   log.Data retrieved and assigned
   the last two logs would ideally be called after getData

None of the calls or functions outside of the ones provided are return promises, I'm working on legacy code and I'm moving away from the setTimeout trick as well as my results weren't consistent.

--UPDATE 2 --

The problem I'm having is known as Forking/Splitting. I just need to figure out chaining specifically to fix my issue.

-- FINAL --

this is what I ended up working out

 // execute promise chain

mainPromise()
    .then(getData);

//the timeout is a little hack to ensure the sequence is kept
mainPromise()
    .then(() => {
        setTimeout(() => {
            myObj.updateProductHTML();
            myObj.updateDOM();
        }, 0);

    });

apparently .then(foo).then(bar) just runs foo and bar at the same time

seems to be working ok right but I feel like somethings not right with it still.

Upvotes: 1

Views: 487

Answers (1)

samanime
samanime

Reputation: 26625

I believe it's because Promise.resolve() doesn't do quite what you think it does.

Promise.resolve() creates a new Promise and resolves it immediately using the value of what it's given. Things like setTimeout return their id (an integer) immediately, so they aren't doing what you want. Your getProducts() is probably an async call, so it may be returning null or something as well (if it's returning a Promise or returns the value synchronously, then it's fine).

You're better off writing a normal Promise and calling resolve() at the appropriate time.

const mainPromise = () => Promise.resolve(
    console.log('spinner spinning...')
    ...spinner code....
);

// Assuming it's already returning a Promise or synchronous response. If it isn't, then deal with it like the setTimeout ones below.
const getData = () => someObj.getProducts('data.json')

const updateProduct = () => new Promise(resolve => {
    setTimeout(()=>{
        someObj.updateProductHTML();
        resolve();
    }, 0)
});

// You don't NEED to in your example since it's at the end of the chain, but you probably want to wrap this too in case you add to the chain.
const updateDom = () => new Promise(resolve => {
    setTimeout(()=>{
        someObj.updateDOM();
        resolve();
    }, 0)
});

Upvotes: 3

Related Questions