用承诺处理一系列对象 [英] dealing with an array of objects with promises

查看:63
本文介绍了用承诺处理一系列对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一个节点表达应用程序,在该应用程序中,我从不同的url获取数据,并调用node-fetch来提取某些页面的主体以及有关某些url端点的其他信息.然后,我想呈现一个html表以通过一系列信息显示此数据.我在呈现信息的调用时遇到了麻烦,因为所有功能都是异步的,这使得在进行呈现页面的调用之前很难确保已解决所有的Promise调用.我一直在研究使用bluebird和.finally()和.all()的其他Promise调用,但是它们似乎不适用于我的数据,因为它不是Promise调用的数组,而是对象的数组.每个对象都是4个promise调用,以获取与一行中的表的某一列有关的数据.解决所有诺言后,是否有功能或特定方式呈现页面?

I am trying to make a node express app where I fetch data from different url's making a call to node-fetch to pull the body of some pages and other information about certain url endpoints. I want to then render a html table to display this data through an array of information. I am having trouble with the call to render the information as all the functions are asynchronous making it difficult to make sure all the promise calls have been resolved before making my call to render the page. I have been looking into using bluebird and other promise calls of .finally() and .all() but they don't seem to work on my data as it is not an array of promise calls, but an array of objects. Each object was 4 promise calls to fetch data relating to a column of my table all in one row. Is there a function or specific way to render the page after all promises are resolved?

var express = require('express');
var fetch = require('node-fetch');
fetch.Promise = require('bluebird');
var router = express.Router();
const client = require('../platform-support-tools');


function makeArray() {
    var registry = client.getDirectory();

    var data_arr = [];
    for (var i = 0; i < registry.length; i++) {
        var firstUp = 0;
        for (var j = 0; i < registry[i]; j++) {
            if (registry[i][j]['status'] == 'UP') {
                firstUp = j;
                break;
            }
        }
        var object = registry[i][firstUp];
        
        data_arr.push({
            'name': object['app'],
            'status': object['status'],
            'swagUrl': object['homePageUrl'] + 'swagger-ui.html',
            'swag': getSwag(object),
            'version': getVersion(object['statusPageUrl']),
            'timestamp': getTimestamp(object['statusPageUrl']),
            'description': getDescription(object['healthCheckUrl'])
        });
    }
    return data_arr;
}

function getSwag(object_in) {
    var homeUrl = object_in['homePageUrl'];
    if (homeUrl[homeUrl.length - 1] != '/'){
        homeUrl += '/';
    }
    var datum = fetch(homeUrl + 'swagger-ui.html')
        .then(function (res) {
            return res.ok;
        }).catch(function (err) {
            return 'none';
        });
    return datum;
}


function getVersion(url_in) {
    var version = fetch(url_in)
        .then(function(res) {
            return res.json();
        }).then(function(body) {
            return body['version'];
        }).catch(function (error) {
            return 'none';
        });
    return version;
}

function getTimestamp(url_in) {
    var timestamp = fetch(url_in)
        .then(function(res) {
            return res.json();
        }).then(function(body) {
            return body['timestamp'];
        }).then(function (res) {
            return body['version'];
        }).catch(function (error) {
            return 'none';
        });
    return timestamp;
}

function getDescription(url_in) {
    var des = fetch(url_in)
        .then(function(res) {
            return res.json();
        }).then(function(body) {
            return body['description'];
        }).catch(function (error) {
            return 'none';
        });
    return des;
}


/* GET home page. */
router.get('/', function (req, res, next) {
    var data_arr = makeArray();
    
    Promise.all(data_arr)
        .then(function (response) {
            //sorting by app name alphabetically
            response.sort(function (a, b) {
                return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0);
            });
            res.render('registry', {title: 'Service Registry', arr: response})
        }).catch(function (err) {
        console.log('There was an error loading the page: '+err);
    });
});

推荐答案

要等待所有这些承诺,您必须将它们放入数组中,以便可以在它们上使用Promise.all().您可以这样做:

To wait on all those promises, you will have to put them into an array so you can use Promise.all() on them. You can do that like this:

let promises = [];
for (item of data_arr) {
    promises.push(item.swag);
    promises.push(item.version);
    promises.push(item.timestamp);
    promises.push(item.description);
}
Promise.all(promises).then(function(results) {
    // all promises done here
})


如果您想要所有这些承诺中的值,请返回该对象中进行更多工作.


If you want the values from all those promises, back into the object that's a bit more work.

let promises = [];
for (item of data_arr) {
    promises.push(item.swag);
    promises.push(item.version);
    promises.push(item.timestamp);
    promises.push(item.description);
}
Promise.all(promises).then(function(results) {
    // replace promises with their resolved values
    let index = 0;
    for (let i = 0; i < results.length; i += 4) {
         data_arr[index].swag = results[i];
         data_arr[index].version = results[i + 1];
         data_arr[index].timestamp = results[i + 2];
         data_arr[index].description = results[i + 3];
         ++index;
    });
    return data_arr;
}).then(function(data_arr) {
    // process results here in the array of objects
});

如果您不得不这样做一次,那么您可以删除属性名称的硬编码,并可以迭代所有属性,收集包含promise的属性名称,然后自动处理它们.

If you had to do this more often that just this once, you could remove the hard coding of property names and could iterate all the properties, collect the property names that contain promises and automatically process just those.

而且,这是一个更通用的版本,它采用对象数组,其中对象上的某些属性是应许的.此实现修改了就位对象的promise属性(它不会复制对象的数组).

And, here's a more general version that takes an array of objects where some properties on the objects are promises. This implementation modifies the promise properties on the objects in place (it does not copy the array of the objects).

function promiseAllProps(arrayOfObjects) {
    let datum = [];
    let promises = [];

    arrayOfObjects.forEach(function(obj, index) {
        Object.keys(obj).forEach(function(prop) {
            let val = obj[prop];
            // if it smells like a promise, lets track it
            if (val && val.then) {
                promises.push(val);
                // and keep track of where it came from
                datum.push({obj: obj, prop: prop});
            }
        });
    });

    return Promise.all(promises).then(function(results) {
        // now put all the results back in original arrayOfObjects in place of the promises
        // so now instead of promises, the actaul values are there
        results.forEach(function(val, index) {
            // get the info for this index
            let info = datum[index];
            // use that info to know which object and which property this value belongs to
            info.obj[info.prop] = val;
        });
        // make resolved value be our original (now modified) array of objects
        return arrayOfObjects;
    });
}

您将这样使用:

// data_arr is array of objects where some properties are promises
promiseAllProps(data_arr).then(function(r) {
    // r is a modified data_arr where all promises in the 
    // array of objects were replaced with their resolved values
}).catch(function(err) {
    // handle error
});


使用 Bluebird承诺库,您可以同时使用两个Promise.map()Promise.props(),上面的功能就是这样:


Using the Bluebird promise library, you can make use of both Promise.map() and Promise.props() and the above function would simply be this:

function promiseAllProps(arrayOfObjects) {
    return Promise.map(arrayOfObjects, function(obj) {
        return Promise.props(obj);
    });
}

Promise.props()迭代一个对象,以查找所有具有诺言的属性,并使用Promise.all()等待所有这些诺言,并返回具有所有原始属性的新对象,但将诺言替换为已解析的值.由于我们有一个对象数组,因此我们使用Promise.map()进行迭代并等待对象的整个数组.

Promise.props() iterates an object to find all properties that have promises as values and uses Promise.all() to await all those promises and it returns a new object with all the original properties, but the promises replaced by the resolved values. Since we have an array of objects, we use Promise.map() to iterate and await the whole array of those.

这篇关于用承诺处理一系列对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆