【问题标题】:How do I mix all this logic with javascript Promises?如何将所有这些逻辑与 javascript Promises 混合在一起?
【发布时间】:2016-07-26 06:06:21
【问题描述】:

我在 Node 中使用 bluebird,但我对使用 Promises 还是很陌生,尤其是当事情开始超出基础时。

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

这是我的伪代码函数,目前是同步的,除了对现有的返回承诺服务的调用...

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 ???;
}

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

任何帮助将不胜感激。

【问题讨论】:

    标签: javascript node.js promise bluebird


    【解决方案1】:

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

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

    代码:

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

    【讨论】:

    • 使用 var 被认为是不好的做法。在这段代码中,let 也不需要声明承诺。 const 是更好的选择,因为不会重新分配 promises 变量。
    • 好,可靠的答案。感谢您帮助我了解退货只需要确保完成所有内部承诺即可。我选择另一个答案只是因为它为如何解决逻辑提供了另一种观点,但你得到了支持。
    【解决方案2】:

    这就是我要解决的方法。

    • 如果所有的承诺都解决了,那么 q.all() 将被解决。每个 Promise 都是模型中要处理的一个属性。
    • 对于每个属性(我会使用 lodash 和 _.reduce 之类的库,但如果您愿意,可以使用 hasOwnProperty)。反正foreach属性,resolveModelProperty函数返回一个promise,它决定了属性的命运,如果有查询名,获取它,如果没有并且有查询,解决它,如果没有,不要更改属性。
    • 对于辅助函数,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);
    }

    【讨论】:

    • 当问题被明确标记为使用 Promise.all() 的 Bluebird 时,您为什么要使用 q.all()
    • 重点是展示如何在 Promise 中完成逻辑。 Promise 库的全局变量的名称可能会有所不同,答案仍然成立。 angularjs 使用 $q。
    • 只是不知道为什么当问题明确要求 Bluebird 时你会使用 q 语法。
    • 感谢您的回答,尤其是逻辑的替代解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 2021-05-31
    • 1970-01-01
    • 2013-05-07
    相关资源
    最近更新 更多