Javascript Don';t在顺序链式承诺中包含q承诺结果

Javascript Don';t在顺序链式承诺中包含q承诺结果,javascript,promise,q,Javascript,Promise,Q,我有以下顺序链接的Q promise,它填充了用户->属性->租户->提醒的层次结构: return getAllUsers() // get all users of the system .then(function(users) { return Q.all(users.map(function(user) { return getUserProperties(user) // foreach user of the syst

我有以下顺序链接的Q promise,它填充了用户->属性->租户->提醒的层次结构:

    return getAllUsers()    // get all users of the system
    .then(function(users) {
        return Q.all(users.map(function(user) {
            return getUserProperties(user)  // foreach user of the system get their properties
            .then(function(properties) {
                user.properties = properties;
                return Q.all(properties.map(function(property) {
                    return getPropertyTenants(property) // foreach property get active tenants
                    .then(function(tenants) {
                        property.tenants = tenants;
                        return Q.all(tenants.map(function(tenant) {
                            return getTenantReminders(property, tenant) // foreach tenant get their payment reminders
                            .then(function(reminders) {
                                // if reminders.length == 0 we don't want to include this user
                                tenant.reminders = reminders;
                            });
                        }));
                    });
                }));
            }).thenResolve(user);
        }));
    });
此承诺链的要点是获取租户的所有付款提醒,然后向每个用户发送一封电子邮件,其中包含租户提醒列表(每个用户)。如果没有从getTenantReminders()解析的提醒,则理想情况下,顶级getAllUsers()的用户不会包含在结果中

我考虑过从getTenantReminders().then()处理程序中抛出一个特殊错误,该处理程序沿着链向上,在thenResolve(user)中处理,然后该处理程序不返回用户。不确定这是不是正确的方法


感谢您的建议。

正如赛斯所说,保持头脑清醒的关键是避免厄运金字塔。以下是一种我认为应该有效的方法(尽管我显然没有对其进行测试):

//生成一个以值数组作为输入的函数,
//将func()应用于它们中的每一个,并将结果合并到
//承诺使用单个阵列。
//假定func()以单个值作为输入并
//返回数组或数组的承诺
//(X->承诺)->(X[]->承诺)
函数applyAllAndMerge(func){
返回函数(值){
返回Q.all(values.map(func))
.then(函数(数组){
返回Array.prototype.concat.apply([],数组);
});
};
}
//返回对所有租户提醒的数组的承诺
//指定属性
//财产->承诺
函数getTenantRemindersForProperty(属性){
返回GetPropertyEnablets(属性)
.然后(applyAllAndMerge)(函数(租户){
返回getTenantReminders(属性、租户);
}));
}
//返回对所有租户提醒的数组的承诺
//指定用户
//用户->承诺
函数getTenantRemindersForUser(用户){
返回getUserProperties(用户)
。然后(applyAllAndMerge(getTenantRemindersForProperty));
}
//返回包含指定值的对象的承诺
//用户及其所有租户提醒
//用户->承诺
函数getUserAndTenants(用户){
返回getTenantRemindersForUser(用户)
.然后(功能(提醒){
返回{用户:用户,提醒:提醒};
});
}        
return getAllUsers()//获取系统的所有用户
.then(功能(用户){
返回Q.all(users.map(getUserAndTenants));
})
.then(功能(用户提醒){
//摆脱没有提醒的用户
var userswithrementers=userrementers.filter(函数(ur){
返回ur.reminders.length>0;
});
//使用用户提醒
});

试着避免这种情况。利用承诺的力量。这段代码在bluebird中可能会更好。只是说说而已。@Seth:这不是一个末日金字塔-它只是一个使用承诺的四级嵌套循环。即使没有命名函数,也可以将其简化很多,以避免@Bergi的深度嵌套。@Seth:请给出一个答案,说明如何进行嵌套:-)当然,您可以通过函数调用来避免嵌套,但是我认为嵌套结构在这里是很自然的。在未关闭
applyAllAndMerge
函数调用结束参数时,在
getTenantRemindersForProperty
上出现了小语法错误。另外,该示例非常适合将提醒对象展平并合并到每个用户的单个数组中
applyAllAndMerge
函数是实现这一点的便捷方法。@Derek谢谢!固定的。
// Produces a function that takes an array of values as input,
// Applies func() to each of them, and merges the results into a 
// promise for a single array.
// func() is assumed to take a single value as input and 
// return an array or promise for an array
// (X -> Promise<Y[]>) -> (X[] -> Promise<Y[]>)
function applyAllAndMerge(func) {
    return function (values) {
        return Q.all(values.map(func))
        .then(function (arrays) {
            return Array.prototype.concat.apply([], arrays);
        });
    };
}

// returns a promise for an array of all tenant reminders for the
// specified property
// property -> Promise<tenantReminder[]>
function getTenantRemindersForProperty(property) {
    return getPropertyTenants(property)
    .then(applyAllAndMerge(function (tenant) {
        return getTenantReminders(property, tenant);
    }));
}

// returns a promise for an array of all tenant reminders for the 
// specified user
// user -> Promise<tenantReminder[]>
function getTenantRemindersForUser(user) {
    return getUserProperties(user)
    .then(applyAllAndMerge(getTenantRemindersForProperty));
}

// returns a promise for an object containing the specified
// user and all of their tenant reminders
// user -> Promise<{user, tenantReminder}[]>
function getUserAndTenants(user) {
    return getTenantRemindersForUser(user)
    .then(function (reminders) {
        return { user: user, reminders: reminders };
    });
}        

return getAllUsers()    // get all users of the system
.then(function(users) {
    return Q.all(users.map(getUserAndTenants));
})
.then(function (userReminders) {
    // get rid of users with no reminders
    var usersWithReminders = userReminders.filter(function (ur) {
        return ur.reminders.length > 0;
    });

    // use usersWithReminders
});