最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Dynamically fill a Promise.all() - Stack Overflow

programmeradmin0浏览0评论

I'm trying to figure out why this bit of code isn't working. I'm looping through a dependency tree (deepObject), and for each one I want to run a function which returns a promise. I would then like for the next set of functions to happen after the resolution of all the promises, but the console logs inside the promise.all are not executing. ES6 is cool too, if you have a better approach, however I would also really like to know why this code is not working.

updated to add .catch (this had no effect)

for (let i = 0; i < keys.length; i++) {
    promisesArray.push(promiseFunction(deepObject[keys[i]]));
}
Promise.all(promisesArray).then(resolved => {
    console.log('dep promises resolved');
    console.log(`resolved: ${JSON.stringify(resolved)}`);
}).catch(err => console.error(new Error(err));

// promiseFunction is recursive
promiseFunction(obj) {
    return new Promise((resolve, reject) => {

        const keys = Object.keys(deepObj);
        for (let j = 0; j < keys.length; j++) {
            if (Object.keys(deepObj[keys[j]]).length) {
                // adding return statement to following line breaks it
                // that was already remended, see threads
                promiseFunction(deepObj[keys[j]]);
            } else {
                const dep = new Package(keys[j]);
                console.log(`skan dep: ${keys[j]}`);
                dep.fetch().then(() => {
                    return anotherFunction();
                }).then(() => {
                    return Promise.all([
                        promise1(),
                        promise2(),
                        promise3(),
                    ]).then(resolved => {
                        if (resolved[0].propertyINeed) {
                            resolve(true);
                        }
                        resolve(false);
                    });
                }).catch(err => {
                    console.error(new Error(err));
                    process.exit(1);
                });
            }
        }
    });

I know this conversation - has been discussed - on here before

In the second link above the accepted answer suggests:

In case you are asynchronously filling the array, you should get a promise for that array, and use .then(Promise.all.bind(Promise)). If you don't know when you stop adding promises, this is impossible anyway as they might never all be resolved at all.

However I'm not using async to fill the array. Do I need this? What am I missing here?

update

Since I have error logging now in both the .then() as well as the .catch() it seems like something is going wrong unrelated to what happens inside of it.

Adding the return statement before promiseFunction(deepObj[keys[j]]); broke the recursion. I went from iterating over 173 objects to 68. Adding the catch logged no additional results. Code above is updated to share more of the recursive fn. When I run it, it seems to execute all the promises, but I have no way of knowing that. I'm most concerned with knowing 1. that the promise array for promise.all contains all the objects it should and 2. catching the moment when all of those promises for all the objects inside the recursed object are resolved.

Also, for the record, each one of these functions that return promises are all necessarily async. I have gone back through all of this multiple times in an attempt to simplify and remove any unnecessary promises. The task is just plex. There are a series of steps that must execute, they are async, and they are chained because they must be resolved in a specific order.

I'm trying to figure out why this bit of code isn't working. I'm looping through a dependency tree (deepObject), and for each one I want to run a function which returns a promise. I would then like for the next set of functions to happen after the resolution of all the promises, but the console logs inside the promise.all are not executing. ES6 is cool too, if you have a better approach, however I would also really like to know why this code is not working.

updated to add .catch (this had no effect)

for (let i = 0; i < keys.length; i++) {
    promisesArray.push(promiseFunction(deepObject[keys[i]]));
}
Promise.all(promisesArray).then(resolved => {
    console.log('dep promises resolved');
    console.log(`resolved: ${JSON.stringify(resolved)}`);
}).catch(err => console.error(new Error(err));

// promiseFunction is recursive
promiseFunction(obj) {
    return new Promise((resolve, reject) => {

        const keys = Object.keys(deepObj);
        for (let j = 0; j < keys.length; j++) {
            if (Object.keys(deepObj[keys[j]]).length) {
                // adding return statement to following line breaks it
                // that was already remended, see threads
                promiseFunction(deepObj[keys[j]]);
            } else {
                const dep = new Package(keys[j]);
                console.log(`skan dep: ${keys[j]}`);
                dep.fetch().then(() => {
                    return anotherFunction();
                }).then(() => {
                    return Promise.all([
                        promise1(),
                        promise2(),
                        promise3(),
                    ]).then(resolved => {
                        if (resolved[0].propertyINeed) {
                            resolve(true);
                        }
                        resolve(false);
                    });
                }).catch(err => {
                    console.error(new Error(err));
                    process.exit(1);
                });
            }
        }
    });

I know this conversation - has been discussed - on here before

In the second link above the accepted answer suggests:

In case you are asynchronously filling the array, you should get a promise for that array, and use .then(Promise.all.bind(Promise)). If you don't know when you stop adding promises, this is impossible anyway as they might never all be resolved at all.

However I'm not using async to fill the array. Do I need this? What am I missing here?

update

Since I have error logging now in both the .then() as well as the .catch() it seems like something is going wrong unrelated to what happens inside of it.

Adding the return statement before promiseFunction(deepObj[keys[j]]); broke the recursion. I went from iterating over 173 objects to 68. Adding the catch logged no additional results. Code above is updated to share more of the recursive fn. When I run it, it seems to execute all the promises, but I have no way of knowing that. I'm most concerned with knowing 1. that the promise array for promise.all contains all the objects it should and 2. catching the moment when all of those promises for all the objects inside the recursed object are resolved.

Also, for the record, each one of these functions that return promises are all necessarily async. I have gone back through all of this multiple times in an attempt to simplify and remove any unnecessary promises. The task is just plex. There are a series of steps that must execute, they are async, and they are chained because they must be resolved in a specific order.

Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Jun 11, 2018 at 9:30 KrakenKraken 5,9403 gold badges31 silver badges52 bronze badges 14
  • 4 try console logging the reject function also to see if something is failing – Semi-Friends Commented Jun 11, 2018 at 9:33
  • 3 "promiseFunction omitted for brevity " —Don't do that. You don't need to provide the real thing, but you do need to provide a minimal reproducible example. I've guessed at what code could go in the missing places and I can't reproduce the problem: jsbin./fesudezuja/1/edit?js,console – Quentin Commented Jun 11, 2018 at 9:34
  • 3 Try Promise.all(promisesArray).then(...).catch(err => console.error('Failed', err)). – dfsq Commented Jun 11, 2018 at 9:36
  • 1 In promiseFunction, the first block of the if statement should return the result of the second promiseFunction - otherwhise it will not resolve to anything! – Fabio Lolli Commented Jun 11, 2018 at 9:45
  • 2 Avoid the Promise constructor antipattern! – Bergi Commented Jun 11, 2018 at 11:04
 |  Show 9 more ments

2 Answers 2

Reset to default 4
if (Object.keys(obj[keys[j]]).length) {
    promiseFunction(obj[keys[j]]);
} else {
    // and some more async hell that all resolves correctly

If Object.keys(obj[keys[j]]).length is true then you never call resolve or reject so the promise never resolves.

(Note that calling promiseFunction recursively creates a new promise which is never put into Promise.all).

Since some of your promises don't resolve, Promise.all won't either.


You probably need something more along the lines of:

var promises = [];
processObject(obj);
Promise.all(promises).then(etc etc);

function processObject(object) {
    for ( loop; over; object ) {
        if (condition) {
             processObject(object[something]);
        } else {
             promises.push(new Promise( (res, rej) => {
                 // so something async
             });
        }
    }
}

Let's have a look at your promiseFunction...

for (let j = 0; j < keys.length; j++) {
    if (Object.keys(obj[keys[j]]).length) {
        //if you get in here, promiseFunction returns undefined, and it never gets resolved
        promiseFunction(obj[keys[j]]);
    } else {
        const dep = new Package(keys[j]);
        console.log(`skan dep: ${keys[j]}`);
        // and some more async hell that all resolves correctly
        //but even if it resolves correctly, you still have the if...
    }
}

To do the trick, just return your promiseFunction result in the if statement:

for (let j = 0; j < keys.length; j++) {
    if (Object.keys(obj[keys[j]]).length) {
        //if you get in here, you're saying this promise will depend on how this second promiseFunction will resolve
        return promiseFunction(obj[keys[j]]);
    } else {
        //omitted for brevity...
        resolve('your value');
    }
}

Now when you go into the if statement, you're basically telling the promise to solve based on whether that second promiseFunction has solved correctly - you're delegating the resolution to another Promise.

I never heard anybody give it this name, but you can think of this as Promise recursion :)

发布评论

评论列表(0)

  1. 暂无评论