如何使用嵌套协同程序和承诺简化JS代码?

时间:2016-06-02 13:45:50

标签: javascript node.js promise bluebird

我有这个工作代码片段,我真的很想简化。它的目标是 Node.js v6.0 ,包 bluebird&共即可。这是一个典型的情况,我想说明代码是紧凑的,易于理解,所以我可以在其他项目中重用它。

该函数返回一个包含多个项目类别(1:m)的清单,每个类别包含多个项目(1:m:n)。所以它是一个具有2个嵌套级别的对象

Root: Checklist
    Level 1: Checklist Item Group(s)
        Level 2: Checklist Item(s)

可以通过屈服在生成器函数中实现根级别(1个核对表)和一个级别(核对表项目类别)。

1:n:m级别不能使用" yield"什么时候我会用Promise.mapSeries()over checklist .__ node__ChecklistItemGroups因为" yield"仅在主生成器函数中支持,而不在map内部函数中支持。所以我回到函数Promise.each()和Promise.then()构造。

function getGraphChecklistById(pId) {
    return co(function *() {
        let checklist = yield getChecklistById(pId); // Returns a promise.
        checklist.__node__ChecklistItemGroups = yield fetchChecklistItemGroupsByChecklistId(pId); // Returns a promise.
        return checklist;
    })
        .then(function (checklist) {
            return Promise.each(
                checklist.__node__ChecklistItemGroups,
                function (pItem) {
                    return fetchChecklistItemsByXrefId(pItem.xchlclig_id).then(function (result) {  // fetchChecklistItemsByXrefId() returns a promise.
                        pItem.__node__ChecklistItems = result;
                    });
                })
                .then(function (unused) {
                    return checklist;
                });
        })
}

这是一个示例结果:

result: {
    "checklist-field-1": 1,
    "checklist-field-2": 1,
    "__node__ChecklistItemGroups": [
        {
            "checklist-group-field-1": 1,
            "checklist-group-field-2": 1,
            "__node__ChecklistItems": [
                {
                    "checklist-item-field-1": 1,
                    "checklist-item-field-2": 1,
                },
                {
                    "checklist-item-field-1": 2,
                    "checklist-item-field-2": 2,
                }
            ]
        },
        {
            "checklist-group-field-1": 2,
            "checklist-group-field-2": 2,
            "__node__ChecklistItems": [
                {
                    "checklist-item-field-1": 1,
                    "checklist-item-field-2": 1,
                },
                {
                    "checklist-item-field-1": 2,
                    "checklist-item-field-2": 2,
                }
            ]
        }
    ]
}

Promise / Coroutines专家的任何建议?谢谢你的时间。

1 个答案:

答案 0 :(得分:4)

我这样写 - 没有Promise.each但只有一个简单的循环:

let getGraphChecklistById = Promise.coroutine(function*(pId) {
//                          ^^^^^^^^^^^^^^^^^ Don't put co(…) in a function, wrap directly
    let checklist = yield getChecklistById(pId);
    checklist.__node__ChecklistItemGroups = yield fetchChecklistItemGroupsByChecklistId(pId); // Returns a promise.
    for (let pItem of checklist.__node__ChecklistItemGroups) {
//  ^^^ iteration in series like Promise.each does it
        let result = yield fetchChecklistItemsByXrefId(pItem.xchlclig_id);
//                   ^^^^^ You can use yield here as it's not an extra function
        pItem.__node__ChecklistItems = result;
    }
    return checklist;
});

您是否使用Bluebird' Promise.coroutineco.wrap并不重要。

如果你想并行迭代这些组,你仍然可以在回调函数中使用yield,如果你把它作为一个生成器:

let getGraphChecklistById = Promise.coroutine(function*(pId) {
    let checklist = yield getChecklistById(pId); 
    checklist.__node__ChecklistItemGroups = yield fetchChecklistItemGroupsByChecklistId(pId); // Returns a promise.
    yield Promise.map(
        checklist.__node__ChecklistItemGroups,
        Promise.coroutine(function*(pItem) {
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ pass this as the promise-returning callback function
            let result = yield fetchChecklistItemsByXrefId(pItem.xchlclig_id);
            pItem.__node__ChecklistItems = result;
        })
    );
    return checklist;
});