如何将所有这些逻辑与javascript Promises混合使用?

时间:2016-07-26 06:06:21

标签: javascript node.js promise bluebird

我在Node中使用bluebird,我仍然很擅长使用Promises,特别是当事情开始超越基础时。

这是我需要使用Promises构建的函数,我正在努力找出设置它的最佳方法。在较高级别,此函数将获取模型对象,并将其返回,将任何查询属性转换为其结果集。例如,属性的值可以是“query(top5Products)”,我们需要查找该命名查询并将该值替换为该查询的结果。属性也可以是实际的基于字符串的查询(使用RQL,例如“eq(contentType,products)&& limit(5,0)”)然后,这个转换后的模型对象将用于绑定模板。

这是我的伪编码函数,当前是同步的,除了对现有的promise返回服务的调用...

function resolveQueryPropertiesOnModel(model) {
    for (let property in model) {
        if (model.hasOwnProperty(property)) {
            let queryName = this.getNameOfNamedQuery(model[property]); // will return undefined if the property is not a named query
            if (queryName) {
                // this property is a named query, so get it from the database
                this.getByName(queryName)
                    .then((queryObject) => {
                        // if queryObject has a results propery, that's the cached resultset - use it
                        if (queryObject && queryObject.results) {
                            model[property] = queryObject.results;
                        }
                        else {
                            // need to resolve the query to get the results                            
                            this.resolve(queryObject.query)
                                .then((queryResults) => {
                                    model[property] = queryResults;
                                });
                        }

                    };
            }
            else if (this.isQuery(model[property]) { // check to see if this property is an actual query
                // resolve the query to get the results
                this.resolve(model[property])
                    .then((queryResults) => {
                        model[property] = queryResults;
                    });                    
            }
        }
    }
    // return some sort of promise that will eventually become the converted model,
    // with all query properties converted to their resultsets
    return ???;
}

在采用逻辑循环和一些预先存在的承诺并将它们混合在一起时,我仍然非常生疏。

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

以下是使用Bluebird执行这些结构更改的代码实现:

  1. 运行外部for循环并收集已启动的任何承诺
  2. 返回嵌套的promises链接它们以便它们被链接,因此顶级promise将指示何时在该链中完成所有操作
  3. 将任何新的承诺收集到promises数组
  4. 使用Promise.all(promises)跟踪所有异步承诺操作何时完成并返回。
  5. 看来你的结果是修改models对象的副作用,因此没有通过promises返回显式值。您可以使用返回的promise来了解所有异步操作何时完成,然后您可以检查model对象的结果。
  6. 代码:

    function resolveQueryPropertiesOnModel(model) {
        const promises = [];
        for (let property in model) {
            let p;
            if (model.hasOwnProperty(property)) {
                let queryName = this.getNameOfNamedQuery(model[property]); // will return undefined if the property is not a named query
                if (queryName) {
                    // this property is a named query, so get it from the database
                    p = this.getByName(queryName).then((queryObject) => {
                        // if queryObject has a results propery, that's the cached resultset - use it
                        if (queryObject && queryObject.results) {
                            model[property] = queryObject.results;
                        } else {
                            // need to resolve the query to get the results                            
                            return this.resolve(queryObject.query).then((queryResults) => {
                                model[property] = queryResults;
                            });
                        }
                    };
                } else if (this.isQuery(model[property]) { // check to see if this property is an actual query
                    // resolve the query to get the results
                    p = this.resolve(model[property]).then((queryResults) => {
                        model[property] = queryResults;
                    });                    
                }
            }
            // if we started a new promise, then push it into the array
            if (p) {
                promises.push(p);
            }
        }
        return Promise.all(promises);
    }
    

答案 1 :(得分:1)

这就是我解决它的方法。

  • 如果所有承诺都得到解决,q.all()将被解析。每个promise都是处理模型中的一个属性。
  • 对于每个属性(我使用像lodash和_.reduce这样的库,但如果你愿意,可以使用hasOwnProperty)。无论如何,foreach属性,resolveModelProperty函数返回一个承诺,决定属性的命运,如果有查询名称,得到它,如果没有,有查询,解决它,如果没有,不要改变属性
  • 到辅助函数,resolveByName和resolveQuery将处理缓存和未缓存查询的情况。



function resolveQueryPropertiesOnModel(model) {
   const promises = [],
        resolveQuery = toBeResolved => this.resolve(toBeResolved),
        resolveByName = queryName => this.getByName(queryName)
		  .then(queryObject => queryObject && queryObject.results 
                   ? queryObject.results : resolveQuery(queryObject.query)),
        resolveModelProperty = (modelProperty) => {
	        const queryName = this.getNameOfNamedQuery(modelProperty);
	        return queryName ? resolveByName(queryName) : 
                  this.isQuery(modelProperty) ? resolveQuery(modelProperty):
                          modelProperty;
        };

	for(let property in model)
		if( model.hasOwnProperty(property)
			promises.push(resolveModelProperty(model[property])
                          .then(result=> model[property]=result));
	return q.all(promises);
}