不要将q承诺包括在顺序链接的承诺中

时间:2015-03-06 19:00:53

标签: javascript promise q

我有以下顺序链接的Q承诺,填写用户 - >属性 - >租户 - >提醒的层次结构:

    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()抛出一个特殊错误。然后()处理程序上传链并在thenResolve(用户)中处理,然后不返回用户。不确定这是否正确。

感谢任何建议。

1 个答案:

答案 0 :(得分:3)

正如赛斯所说,保持理智的关键是避免厄运的金字塔。这是一种我认为应该工作的方法(虽然显然我没有测试过):

// 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
});