我可以在另一个承诺中调用承诺(带有循环)吗?

时间:2016-12-21 23:31:46

标签: javascript node.js mongodb express ejs

我正在尝试使用Ebay API提供的2项服务: findItemsByKeywords(keyword):返回项目列表(对象); getItemTransactions(itemId):返回项目事务列表(对象);

在调用findItemsByKeywords并获取返回的项目列表后,我需要调用getItemTransactions并获取每个项目的交易并使用它们创建新列表。

我正在使用Node.js,Express,Ejs和MongoDB

我的代码仅适用于一次互动。

Error:
Error: unable to connect to database at mongodb://localhost/simplysell-development
    at NativeConnection.<anonymous> (/Users/guilhermefalcao/workspace/simplysell/app.js:11:9)
    at emitOne (events.js:96:13)
    at NativeConnection.emit (events.js:188:7)
    at Db.<anonymous> (/Users/guilhermefalcao/workspace/simplysell/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js:169:10)
    at emitTwo (events.js:106:13)
    at Db.emit (events.js:191:7)
    at Server.listener (/Users/guilhermefalcao/workspace/simplysell/node_modules/mongodb/lib/db.js:1786:14)
    at emitOne (events.js:96:13)
    at Server.emit (events.js:188:7)
    at Server.<anonymous> (/Users/guilhermefalcao/workspace/simplysell/node_modules/mongodb/lib/server.js:274:14)
    at emitOne (events.js:96:13)
    at Server.emit (events.js:188:7)
    at Pool.<anonymous> (/Users/guilhermefalcao/workspace/simplysell/node_modules/mongodb-core/lib/topologies/server.js:334:12)
    at emitOne (events.js:96:13)
    at Pool.emit (events.js:188:7)
    at Connection.<anonymous> (/Users/guilhermefalcao/workspace/simplysell/node_modules/mongodb-core/lib/connection/pool.js:270:12)

我不是想要访问数据库,我不知道为什么会出现这个错误。

我对代码和英语质量感到抱歉, 我现在开始

以下是一些代码:

router.get('/bestsellers', (req, res, next) => {
  var i = 0;
  var findItemsByKeywordsPromise = findItemsByKeywords('iphone');
  findItemsByKeywordsPromise.then(items => {
    var getItemTransactionsPromise = getItemTransactions(items);
    return getItemTransactionsPromise;
  }).then(test => console.log(test))

});

function getItemTransactions(items) {

  return new Promise((resolve, reject) => {
    var list = [];
    items.forEach(function (item) {

      ebay.xmlRequest({
        serviceName: 'Trading',
        opType: 'GetItemTransactions',

        // app/environment
        devId: 'xxxxxxx',
        certId: 'xxxxxxx',
        appId: 'xxxxxxx',
        sandbox: false,

        // per user
        authToken: 'xxxxxxx',

        params: {
          'ItemID': item.itemId,
          'NumberOfDays': 30
        }
      }, function (error, results) {
        list.push(results)
        resolve(list);
      });
    })
  });

}

function findItemsByKeywords(keywords) {

  return new Promise((resolve, reject) => {

    var params = {
      keywords: [keywords],
    };

    ebay.xmlRequest({
      serviceName: 'Finding',
      opType: 'findItemsByKeywords',
      appId: 'xxxx',      // FILL IN YOUR OWN APP KEY, GET ONE HERE: https://publisher.ebaypartnernetwork.com/PublisherToolsAPI
      params: params,
      parser: ebay.parseResponseJson    // (default)
    },
      // gets all the items together in a merged array
      function itemsCallback(error, itemsResponse) {
        if (error) reject(error);

        console.log('findItemsByKeywords called');

        var items = itemsResponse.searchResult.item;

        console.log('Found', items.length, 'items');
        resolve(items);
      }
    );
  });
}

2 个答案:

答案 0 :(得分:-1)

查看代码,我们无法知道Mongo错误发生的原因。

但是回答标题中的答案,函数getItemTransactions是错误的。您正在为数组中的每个项目调用resolve,但Promise只能解析一次,因此它只会返回它解析的第一个项目。

我会用两个函数组织它:

function getItemTransaction (item) {
    return Promise(function (resolve, reject) {
        ebay.xmlRequest({
            serviceName: 'Trading',
            opType: 'GetItemTransactions',

            // app/environment
            devId: 'xxxxxxx',
            certId: 'xxxxxxx',
            appId: 'xxxxxxx',
            sandbox: false,

            // per user
            authToken: 'xxxxxxx',

            params: {
                'ItemID': item.itemId,
                'NumberOfDays': 30
            }
        }, function (error, results) {
            if (error) {
                return reject(error);
            }
            resolve(results);
          });
    });
}


function getItemTransactions(items) {
    var promises = items.map(function(item) {
        return getItemTransaction(item);
    });
    // Promise.all waits for all the promises to get resolved
    // and return an array of resolved promises
    return Promise.all(promises);
}

如果您在主代码中执行该操作,则可能不需要第二个函数:

findItemsByKeywords('iphone')
    .then(items => {
        return Promise.all(items.map(item => getItemTransaction(item));
    })
    .then(test => console.log(test));

答案 1 :(得分:-2)

那是对的。在ebay api返回一个值之前循环完成,因此解析将返回一个不完整的数组(列表)。

function getItemTransactions(items) {

  return new Promise((resolve, reject) => {
    var list = [];
    items.forEach(function (item) {

      ebay.xmlRequest({
        serviceName: 'Trading',
        opType: 'GetItemTransactions',

        // app/environment
        devId: 'xxxxxxx',
        certId: 'xxxxxxx',
        appId: 'xxxxxxx',
        sandbox: false,

        // per user
        authToken: 'xxxxxxx',

        params: {
          'ItemID': item.itemId,
          'NumberOfDays': 30
        }
      }, function (error, results) {
        list.push(results)
        if (list.length == items.length) {
          resolve(list);
        }
      });
    })
  });

}

这是我改变的,我在列表数组完成时解析:

if (list.length == items.length) {
    resolve(list);
}