0

I think this is a really stupid question but I'm having a hard time wrapping my head around promises.

I'm using Q (for nodejs) to sync up a couple of async functions. This works like a charm.

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

The problem I have is with this little function:

  getItemData(itemRequest) 

This function is filled with several of callbacks. The promise chain runs through the function just fine but ignores all the callbacks I use ( eg several XHR calls I make in the function).

A simplified version of the function looks like this (just to give you an idea):

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

The xhr function I use looks like this:

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

So my questions:

  • Can I leave the function unaltered and use the callbacks that are in place ánd the promise chain?
  • Or do I have to rewrite the function to use promises for the XHR?
  • And if so, How can I best write my promise chain? Should I reject the initial promise in the forEach?

Again, sorry if this is a really stupid question but I don't know what the right course of action is here.

Thanks!

[EDIT] Q.nfcall, I don't get it

So I've been looking into Q.nfcall which allows me to use node callbacks. Bu I just don't understand exacly how this works. Could someone give a simple example how I would go about using it for a function with several async xhr calls?

I tried this but as you can see I don't really understand what I'm doing:

    var second = Q.nfcall(second);

    function second (files) {

[EDIT 2]

This is the final funcction in my getitemdata function callback chain. This function basically does the same as the function 'second' but I push the result directly and then return the promise. This works as stated, but without all the additional callback data, because it does not wait for the callbacks to return with any data.

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

2 回答 2

1

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

首先,关于您的原始问题,您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)

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

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

于 2014-05-18T03:49:20.023 回答
0

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

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

于 2013-09-06T15:38:00.850 回答