繁体   English   中英

Q Promise链和NodeJS回调

[英]Q Promise chain and NodeJS callbacks

我认为这是一个非常愚蠢的问题,但我很难兑现承诺。

我正在使用Q(用于nodejs)来同步几个异步函数。 这就像一个魅力。

    var first = function () {
        var d = Q.defer();
        fs.readdir(path,function(err,files){
            if(err) console.log(err);
            d.resolve(files);
        });
        return d.promise;
    };

    var second = function (files) {
        var list = new Array;
        files.forEach(function(value, index){
            var d = Q.defer();
            console.log('looking for item in db', value);
            db.query(
                'SELECT * FROM test WHERE local_name =? ', [value],{
                    local_name      : String,

                },
                function(rows) {
                    if (typeof rows !== 'undefined' && rows.length > 0){
                        console.log('found item!', rows[0].local_name);
                        d.resolve(rows[0]);
                    } else {
                        var itemRequest = value;
                        getItemData(itemRequest);
                    }
                }
            );
            list.push(d.promise);
        });
        return Q.all(list);
    };

    first()
    .then(second)
    .done(function(list){
        res.send(list);
    });

我有这个小功能的问题:

  getItemData(itemRequest) 

此函数包含多个回调。 promise链在整个函数中运行得很好,但是忽略了我使用的所有回调(例如,我在函数中进行的几个XHR调用)。

该函数的简化版本如下所示(仅供参考):

    function getItemData(itemRequest){
        helper.xhrCall("call", function(response) {
            var requestResponse = JSON.parse(response)
            , requestInitialDetails = requestResponse.results[0];

            downloadCache(requestInitialDetails,function(image) {

                    image = localImageDir+requestInitialDetails.image;

                    helper.xhrCall("call2", function(response) {

                        writeData(item,image,type, function(){
                            loadData(item);
                        });
                    });
                } else {
                    writeData(item,image,type, function(){
                        loadData(item);
                    });
                }
            });
        });

我使用的xhr函数如下所示:

  xhrCall: function (url,callback) {
    var request = require("request")
    , colors = require('colors');
    request({
        url: url,
        headers: {"Accept": "application/json"},
        method: "GET"
    }, function (error, response, body) {
        if(!error){
            callback(body);
        }else{
           console.log('Helper: XHR Error',error .red); 
        }
    });
  }

所以我的问题是:

  • 我是否可以保留功能不变,并使用承诺链和适当的回调?
  • 还是我必须重写函数以对XHR使用Promise?
  • 如果是这样,我该如何最好地写出我的诺言链? 我应该拒绝forEach中的最初承诺吗?

再次,如果这是一个非常愚蠢的问题,对不起,但我不知道这里的正确做法是什么。

谢谢!

[编辑] Q.nfcall,我不明白

因此,我一直在研究Q.nfcall,它使我可以使用节点回调。 Bu我只是不完全了解它是如何工作的。 有人可以举一个简单的例子,说明如何将它用于具有多个异步xhr调用的函数吗?

我尝试过此方法,但是如您所见,我不太了解自己在做什么:

    var second = Q.nfcall(second);

    function second (files) {

[编辑2]

这是我的getitemdata函数回调链中的最后一个功能。 该函数与“ second”函数基本相同,但我直接推送结果,然后返回promise。 如上面所述,它可以工作,但是没有所有其他回调数据,因为它不等待回调返回任何数据。

  function loadData(item) {
        var d = Q.defer();
        db.query(
            'SELECT * FROM test WHERE local_name =? ', [item],{
                local_name      : String,

            },
            function(rows) {
                if (typeof rows !== 'undefined' && rows.length > 0){
                    list.push(d.promise);
                } 
            }
        );

    });
    return Q.all(list);
};

第二次编辑后,您的答案还不清楚。

首先,在您的原始问题上,您的getItemData对承诺链没有影响。
您可以更改函数的调用签名,并像这样传递您的延期承诺。

getItemData(itemRequest, d) 

并将这个递延的承诺一直传递到您的xhrCall并在那里解决。

我将重新编写您的整个实现,并确保所有函数都返回promise。

许多人将延迟的承诺视为反模式。 所以我使用和谐定义的Promise API(下一个javascript)

说完之后,我将像这样重新实现您的原始代码(我尚未测试)

var Promise = Promise || require('es6-promise').Promise // a polyfill
;

function errHandler (err){
  throw err
}

function makeQuery () {
  var queryStr = 'SELECT * FROM test WHERE local_name =? '
  , queryOpt = {local_name: String}
  ;
  console.log('looking for item in db', value)

  return new Promise(function(resolve, reject){
    db.query(queryStr, [value], queryOpt, function(rows) {
      if (typeof rows !== 'undefined' && rows.length > 0){
        console.log('found item!', rows[0].local_name);
        resolve(rows[0]);
      } else {
        // note that it returns a promise now.
        getItemData(value).then(resolve).catch(errHandler)
      }
    })
  })
}

function first () {
  return new Promise(function(resolve, reject){
    fs.readdir(path, function(err, files){
      if (err) return reject(err)
      resolve(files)
    })
  })
}

function second (files) {
  return Promise.all(files.map(function(value){
    return makeQuery(value)
  });
}

first()
.then(second)
.then(res.send)
.catch(errHandler)

请注意, Promise API上没有done方法。

新的Promise API的缺点之一是错误处理。 看看bluebird
它是一个健壮的Promise库,它与新的Promise API兼容并且具有许多Q帮助器功能。

据我所知,您需要从getItemData返回一个getItemData 像在second() Q.defer()一样使用Q.defer() ,并在回调完成数据后解析它。 然后,您可以将其推入list

若要保存代码,可以使用Q.nfcall立即调用节点样式回调函数,并返回一个Promise。 请参阅API文档中的示例: https : //github.com/kriskowal/q/wiki/API-Reference#qnfcallfunc-args

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM