Javascript 需要关于嵌套承诺的建议。全部

Javascript 需要关于嵌套承诺的建议。全部,javascript,node.js,es6-promise,Javascript,Node.js,Es6 Promise,在玩现代JS时,遇到了以下问题 考虑通过一些HTTP API和本地Mongo实例来访问ExtSystem。它们都包含具有名称和id的对象 对于Mongo,我将mongoose与ObjectSchema模型{{u id,sourceId,name,internalParam}一起使用,其中sourceId等于ExtSystem中的id,internalParam仅存在于我的应用程序中。对于ExtSystem,有两种方法返回request.js Promise: ExtSystem.all返回id[

在玩现代JS时,遇到了以下问题

考虑通过一些HTTP API和本地Mongo实例来访问ExtSystem。它们都包含具有名称和id的对象

对于Mongo,我将mongoose与ObjectSchema模型{{u id,sourceId,name,internalParam}一起使用,其中sourceId等于ExtSystem中的id,internalParam仅存在于我的应用程序中。对于ExtSystem,有两种方法返回request.js Promise:

ExtSystem.all返回id[id,id,id]的数组 ExtSystem.get返回对象本身{id,name} 还有一个全局函数errHandler,它可以处理request.js和mongoose承诺中的错误。要实现的目标是将Mongo与ExtSystem同步:在Mongo中更新ExtSystem中的所有对象,并从Mongo中删除ExtSystem中不再存在的对象

我想到的是:

ExtSystem.all().then(body => { 
    let basket = []; // will store all promises for both ExtSystem and Mongo requests
    basket.push(...body.map(o => ExtSystem.get(o.id));
    basket.push(ObjectSchema.find({}, 'sourceId'));

    Promise.all(basket).then(basketDoc => {
        let mongoObjects = {}, extObjects = {};
        basketDoc.pop().forEach(o => mongoObjects[o.sourceId] = o._id); // Mongo retuns array of {_id, sourceId } objects
        basketDoc.forEach(o => { // ExtSystem returns array of {id, name} objects
            extObjects[o.id] = {
                sourceId: o.id,
                name: o.name
            }
        });

        let esSet = new Set(Object.keys(extObjects));
        let mongoDeleteIds = Object.keys(mongoObjects).filter(oId => !esSet.has(oId)); // Set.has is faster than Array.indexOf

        let syncPromises = [];
        syncPromises.push(...Object.keys(extObjects).map(oId => ObjectSchema.findOneAndUpdate({ sourceId: extObjects[oId].sourceId }, extObjects[oId], { upsert: true, new: true })));
        syncPromises.push(...mongoDeleteIds.map(oId => ObjectSchema.remove({_id: oId})));

        Promise.all(syncPromises).then(_ => { // I don't need results, only the moment when sync is complete
            ObjectSchema.find().then(doc => { // return actual objects from Mongo
                someBusinessLogic(doc);
            }).catch(errHandler);
        }).catch(errHandler);
    }).catch(errHandler);
}).catch(errHandler);

所以我仍然有4个嵌套的承诺解析,可能遗漏了一些东西。有没有一种最好的方法可以用不太复杂的代码来实现这一点?

您可以从一个用户那里返回一个承诺,然后链接它。因为它可以链接,这意味着所有错误都可以传播到一个处理程序

您的代码基本上可以变成:

ExtSystem.all().then(body => {
    let basket = []; // will store all promises for both ExtSystem and Mongo requests
    basket.push(...body.map(o => ExtSystem.get(o.id));
    basket.push(ObjectSchema.find({}, 'sourceId'));
    return Promise.all(basket);
}).then(basketDoc => {
    let mongoObjects = {}, extObjects = {};
    basketDoc.pop().forEach(o => mongoObjects[o.sourceId] = o._id); // Mongo retuns array of {_id, sourceId } objects
    basketDoc.forEach(o => { // ExtSystem returns array of {id, name} objects
        extObjects[o.id] = {
            sourceId: o.id,
            name: o.name
        }
    });

    let esSet = new Set(Object.keys(extObjects));
    let mongoDeleteIds = Object.keys(mongoObjects).filter(oId => !esSet.has(oId)); // Set.has is faster than Array.indexOf

    let syncPromises = [];
    syncPromises.push(...Object.keys(extObjects).map(oId => ObjectSchema.findOneAndUpdate({ sourceId: extObjects[oId].sourceId }, extObjects[oId], { upsert: true, new: true })));
    syncPromises.push(...mongoDeleteIds.map(oId => ObjectSchema.remove({_id: oId})));
    return Promise.all(syncPromises);
}).then(_ => {
    return ObjectSchema.find();
}).then(doc => {
    return someBusinessLogic(doc);
}).catch(errHandler);

你可以从一家连锁店退回一个承诺。因为它可以链接,这意味着所有错误都可以传播到一个处理程序

您的代码基本上可以变成:

ExtSystem.all().then(body => {
    let basket = []; // will store all promises for both ExtSystem and Mongo requests
    basket.push(...body.map(o => ExtSystem.get(o.id));
    basket.push(ObjectSchema.find({}, 'sourceId'));
    return Promise.all(basket);
}).then(basketDoc => {
    let mongoObjects = {}, extObjects = {};
    basketDoc.pop().forEach(o => mongoObjects[o.sourceId] = o._id); // Mongo retuns array of {_id, sourceId } objects
    basketDoc.forEach(o => { // ExtSystem returns array of {id, name} objects
        extObjects[o.id] = {
            sourceId: o.id,
            name: o.name
        }
    });

    let esSet = new Set(Object.keys(extObjects));
    let mongoDeleteIds = Object.keys(mongoObjects).filter(oId => !esSet.has(oId)); // Set.has is faster than Array.indexOf

    let syncPromises = [];
    syncPromises.push(...Object.keys(extObjects).map(oId => ObjectSchema.findOneAndUpdate({ sourceId: extObjects[oId].sourceId }, extObjects[oId], { upsert: true, new: true })));
    syncPromises.push(...mongoDeleteIds.map(oId => ObjectSchema.remove({_id: oId})));
    return Promise.all(syncPromises);
}).then(_ => {
    return ObjectSchema.find();
}).then(doc => {
    return someBusinessLogic(doc);
}).catch(errHandler);

承诺是为了摆脱厄运金字塔。如果你有嵌套的承诺,那么你是做错了

承诺允许您在通话中返回另一个承诺,以链接它们。因此,不要这样做:

p1.then(stuff => {
    p2.then(stuff =>{
        ...
    });
});
你应该这样做

p1
.then(stuff => {
    return p2;
}).then(stuff => {
    return;
});
如果您有一些变量需要在将来的承诺中访问,您可以将它们作为另一个承诺包含进来,或者使用我刚才创建的一个承诺来创建一个包含全局可重用对象的承诺

Promise
.resolve({})           // creates global object for holding values
.then(obj => {
    return pack(obj, taskPromiseA, "a", taskPromiseB, "b");
})
.then(obj => {        // you can access results from A and B here
    return pack(obj, taskPromiseC, "c");
})
.then(console.log);   // you can access them all here

承诺是为了摆脱厄运金字塔。如果你有嵌套的承诺,那么你是做错了

承诺允许您在通话中返回另一个承诺,以链接它们。因此,不要这样做:

p1.then(stuff => {
    p2.then(stuff =>{
        ...
    });
});
你应该这样做

p1
.then(stuff => {
    return p2;
}).then(stuff => {
    return;
});
如果您有一些变量需要在将来的承诺中访问,您可以将它们作为另一个承诺包含进来,或者使用我刚才创建的一个承诺来创建一个包含全局可重用对象的承诺

Promise
.resolve({})           // creates global object for holding values
.then(obj => {
    return pack(obj, taskPromiseA, "a", taskPromiseB, "b");
})
.then(obj => {        // you can access results from A and B here
    return pack(obj, taskPromiseC, "c");
})
.then(console.log);   // you can access them all here