Nodejs:用生成器函数解析promise

时间:2014-12-20 13:45:21

标签: node.js asynchronous promise generator

我知道网上有很多很好的例子,我读过很多很好的例子,但是目前我还是坚持用nodejs 0.11.x中的生成器的新功能来解决承诺。

例如我有以下功能:

SolrBaseDomain.prototype.promisedQuery = function(query, callback) {
  var solrClient = solr.createClient(this.configuration);
  var defer = Q.defer();

  solrClient.search(query, function(err,obj){
    if (!err) {
        if (obj.response.numFound > 0) {
            defer.resolve(obj.response.docs);
        } else {
            defer.resolve(null);
        }
    } else {
        defer.reject(err);
    }
  });

  var promise = defer.promise;
  return Q.async(function* (){
    var result =  yield promise;
    return result;
  });
};

我希望每次对这个方法的调用都会等到promise被完全填充,并且return语句会返回promise的结果。

但是目前似乎代替里面的代码" Q.async ......"执行方法的return语句后,将不会执行或异步调用到达。

很奇怪,在我知道的每个例子中,这是等待nodejs中的异步调用的推荐方法之一,但目前它对我不起作用。

我已尝试过上述示例的许多不同变体,但结果是每次都相同,我得不到有效的结果。

我在版本0.11.10中安装了nodejs,并且当代码为execute时设置了 - harmony -flag。

有人能指出我正确的方向吗?我想知道我是否监督某事...... :)

感谢您的反馈。

祝你好运

Udo

4 个答案:

答案 0 :(得分:0)

试试这个

SolrBaseDomain.prototype.promisedQuery = Q.async(function*(query) {
  var solrClient = solr.createClient(this.configuration);
  var obj = yield Q.ninvoke(solrClient, "search", query);
  return obj.response.numFound > 0 ? obj.response.docs : null;
});

对于promises,这与回调相同:

SolrBaseDomain.prototype.query = function (query, callback) {
  var solrClient = solr.createClient(this.configuration);
  solrClient.search(query, function(err, obj) {
       if (err) return callback(err);
       callback(null,  obj.response.numFound > 0 ? obj.response.docs : null);
  });
};

因此,如果第一个返回一个解析为undefined的promise,那么回调版本将使用undefined调用回调。

答案 1 :(得分:0)

  

我希望每次对这个方法的调用都会等到promise被完全填充,并且return语句会返回promise的结果。

没有。生成器不会使函数同步,您不能(并且不想)在等待结果时阻塞。当调用生成器函数并按顺序运行它产生的异步步骤时,最终返回的结果仍然是异步的 - 因此是一个承诺。只有生成器中的 ,您的代码才能使用同步控制流和yield

这意味着(then - )基于回调的代码

SolrBaseDomain.prototype.promisedQuery = function(query) {
    var promise = Q.ninvoke(solr.createClient(this.configuration), "search", query);
    return promise.then(function(obj) {
        if (obj.response.numFound > 0) {
            return obj.response.docs;
        } else {
            return null;
        }
    });
};

变为

SolrBaseDomain.prototype.promisedQuery = Q.async(function* (query) {
    var promise = Q.ninvoke(solr.createClient(this.configuration), "search", query);
    var obj = yield promise;
//            ^^^^^
    if (obj.response.numFound > 0) {
        return obj.response.docs;
    } else {
        return null;
    }
});

答案 2 :(得分:0)

根据您的建议,我的代码现在看起来像这样:

... 
SolrBaseDomain.prototype.query = Q.async(function* (query) {
  var solrClient = solr.createClient(this.configuration);
  var obj = yield Q.ninvoke(solrClient, "search", query);
  return obj.response.numFound > 0 ? obj.response.docs : null;
});
...

我在所有数据访问层上共享上述查询功能,以便有一个以异步方式查询不同索引的中心方法。

例如在域数据访问层中,处理该函数的代码如下所示:

SolrHostDomain.prototype.getByName = Q.async(function* (domain) {

var queryObject = {
        "domain": domain
};

var query = this.getQuery("byName", queryObject);
var docs = yield this.query(query);

var domain = null;
if (docs != null && docs.length > 0) {
    domain = this.dataMapper.merge(docs[0]);
}

return domain;});

目前我不确定“getByName”函数中的生成器是否必要,但它似乎有效。处理承诺对我来说是一个不明确的概念,因为我是nodejs的新手。

所以,也许,如果你可以帮我解决这个话题,并指出我正确的方向,这将是有帮助的。

对我来说,主要的问题是,我怎样才能确保同步方法可以调用异步方法并返回不是承诺,而是这个承诺的最终结果。

我已经搜索了很长时间,但是我找不到一个很好的文档来描述生成器函数或promises与同步调用的结合使用。甚至示例都只关注使用机制但不与同步函数一起工作。

致以最诚挚的问候,非常感谢您的帮助

答案 3 :(得分:0)

得到了!!!

经过一些试验和错误后,我想我现在得到了它,并且我有一个有效的解决方案:

查询功能:

SolrBaseDomain.prototype.query = Q.async(function* (query) {
  var solrClient = solr.createClient(this.configuration);
  var obj = yield Q.ninvoke(solrClient, "search", query);
  return obj.response.numFound > 0 ? obj.response.docs : null;
});

通话方式:

SolrHostDomain.prototype.getByName = function(domain) {

var queryObject = {
        "domain": domain
};

var query = this.getQuery("byName", queryObject);
var docsPromise = this.query(query);

var _self = this;
return docsPromise.then(function(docs) {

    var domain = null;
    if (docs != null && docs.length > 0) {
        domain = _self.dataMapper.merge(docs[0]);
    }

    return domain;

});
};

解决方案是要明白,即使使用了yield,“query”-method仍然会返回一个promise而不是具体的结果。

所以我必须在“then”函数中添加正在处理promise的结果的每个代码(如果在方法的调用层次结构中没有其他调用者将跟随,则“完成”)。

在解除承诺后,将处理在“then”功能中设置的每个代码。

BR