2015-11-13 55 views
0

我正在使用Node,Mongoose和Bluebird,並且正在提供多個RSS提要的網站上工作。使用Mongoose FindOne&Bluebird承諾在循環中構建數組承諾

當檢索到訂閱源時,我想將已保存到表格中的任何文章從表格中提取出來,並將它們與訂閱源中的任何新文章結合到一個數組中。我似乎無法找到等待的方法在返回數組之前承諾全部解決。基本問題是,當loadRSSFeed被調用時,它本質上立即調用返回articleList行。如何排除所有這些,直到我的承諾全部解決爲止,什麼都不會返回?

第一個函數只是有點包裝的一切:

function loadRSSFeed(rss, newsSource) { 
var articleList = []; 

// Promise.each(rss.channel[0].item, function (article) { 
rss.channel[0].item.forEach(function (article) { 
    var item = {}; 
    item.link = tryEval(article, "article.link[0]"); 

    Promise(function() { 
     return getArticle(newsSource, article, item, articleList) 
     .then(function() { 
      return articleList; 
     }) 
    }) 
})     
};   

的getArticle功能如下:

function getArticle(newsSource, article, item, articleList) { 
return Articles.findOne({ link: article.link }, function (err, doc) { 
    if (doc) { 
     articleList.push(doc._doc); 
    } 
    else { 
     item.title = tryEval(article, "article.title[0]"); 
     item.pubDate = tryEval(article, "article.pubDate[0]"); 
     item.sourceId = newsSource.id; 
     item.sourceName = newsSource.name; 

     if (item.pubDate) { 
      try { 
       item.pubDate = new Date(item.pubDate); 
      } 
      catch (err) { 
       item.pubDate = ""; 
      } 
     }; 

     item.contentSnippet = tryEval(article, "article.description[0]"); 
     if (item.contentSnippet.indexOf("<") > 0) { 
      item.contentSnippet = item.contentSnippet.substring(0, item.contentSnippet.indexOf("<") - 1); 
     }; 

     item.image = tryEval(article, "article['media:content'][0].$.url|article.thumbnail[0]"); 
     if (!item.image) { 
      item.image = photoHunt(item); 
      if (item.image) { 
       item.contentSnippet = ""; 
      } 
     }; 
     if (item.title && item.link && (item.image || item.contentSnippet)) { 
      articleList.push(saveArticle(item)); 
     } 
    } 
}) 
} 

和saveArticle功能如下:

function saveArticle(article) { 
var curArticle = {}; 

if (article._id) { 
    curArticle = article; 
    curArticle._id = article._id; 
    curArticle.isNew = false; 
} 
else { 
    curArticle = new Articles(); 
    curArticle.title = article.title; 
    curArticle.link = article.link; 
    curArticle.pubDate = article.pubDate; 
    curArticle.image = article.image; 
    curArticle.contentSnippet = article.contentSnippet; 
    curArticle.sourceName = article.name; 
    curArticle.sourceId = article.sourceId; 

    if (article.haters) { 
     curArticle.haters = article.haters; 
    }; 

    if (article.lovers) { 
     curArticle.lovers = article.lovers; 
    }; 

    if (article.readers) { 
     curArticle.readers = article.readers; 
    }; 
} 
curArticle.save(function (err) { 
    if (err) 
     console.log(err); 
}); 
return curArticle; 
}; 

這是Articles模型的外觀,以防萬一這裏出現問題:

var mongoose  = require('mongoose'), 
Schema  = mongoose.Schema; 
// NewsSchema = new Schema({ name: String }); 

var ArticlesSchema = new Schema({ 
title: String, 
link: String, 
pubDate: Date, 
image: String, 
contentSnippet: String, 
sourceName: String, 
lovers: [], 
haters: [], 
readers: [], 
forumLinks: [] 
}); 

module.exports = mongoose.model('Articles', ArticlesSchema); 

回答

2

它看起來對我來說,你可以使用藍鳥的Promise.map()既遍歷所有的RSS提要,並等待它們全部完成:

function loadRSSFeed(rss, newsSource) { 
    // Promise.each(rss.channel[0].item, function (article) { 
    return Promise.map(rss.channel[0].item, function(article) { 
     var item = {}; 
     item.link = tryEval(article, "article.link[0]"); 
     return getArticle(newsSource, article, item, articleList); 
    }).then(function(articleList) { 
     // filter out any empty items 
     return articleList.filter(function(article) { 
      return !!article; 
     }); 
    }); 
} 


function getArticle(newsSource, article, item) { 
    var find = Promise.promisify(Articles.findOne, {context: Articles}); 
    return find({link: article.link}).then(doc) { 
     if (doc) { 
      return doc._doc; 
     } else { 
      item.title = tryEval(article, "article.title[0]"); 
      item.pubDate = tryEval(article, "article.pubDate[0]"); 
      item.sourceId = newsSource.id; 
      item.sourceName = newsSource.name; 
      if (item.pubDate) { 
       try { 
        item.pubDate = new Date(item.pubDate); 
       } catch (err) { 
        item.pubDate = ""; 
       } 
      }; 
      item.contentSnippet = tryEval(article, "article.description[0]"); 
      if (item.contentSnippet.indexOf("<") > 0) { 
       item.contentSnippet = item.contentSnippet.substring(0, item.contentSnippet.indexOf("<") - 1); 
      }; 
      item.image = tryEval(article, "article['media:content'][0].$.url|article.thumbnail[0]"); 
      if (!item.image) { 
       item.image = photoHunt(item); 
       if (item.image) { 
        item.contentSnippet = ""; 
       } 
      }; 
      if (item.title && item.link && (item.image || item.contentSnippet)) { 
       return saveArticle(item); 
      } 
     } 
     // unsure what your code intends if there was no article here 
     // this will return undefined which will get filtered out later 
    }) 
} 

function saveArticle(article) { 
    return new Promise(function(resolve, reject) { 
     var curArticle; 
     if (article._id) { 
      curArticle = article; 
      curArticle._id = article._id;   // don't know why this is needed since curArticle === article already 
      curArticle.isNew = false; 
     } else { 
      curArticle = new Articles(); 
      curArticle.title = article.title; 
      curArticle.link = article.link; 
      curArticle.pubDate = article.pubDate; 
      curArticle.image = article.image; 
      curArticle.contentSnippet = article.contentSnippet; 
      curArticle.sourceName = article.name; 
      curArticle.sourceId = article.sourceId; 
      if (article.haters) { 
       curArticle.haters = article.haters; 
      }; 
      if (article.lovers) { 
       curArticle.lovers = article.lovers; 
      }; 
      if (article.readers) { 
       curArticle.readers = article.readers; 
      }; 
     } 
     curArticle.save(function (err) { 
      if (err) reject(err) else resolve(curArticle); 
     }); 
    }); 
}; 
+0

謝謝!超級接近,如果我看到這個正確的,articleList回到調用函數,因爲看起來是未解決的承諾,新的文章不再被保存 - 我認爲是因爲承諾被擱置。 –

+0

@MikeFeltman - 我錯過了關於'saveArticle()'是異步的部分(我沒有看到)。你是否也需要我來幫助解決這個問題,或者你能否將這些原則應用到這個功能上? – jfriend00

+0

讓我試試看,如果沒有,我會回來的。 :) 再次感謝!我不確定這是唯一的問題,因爲一些文章已經在表格中,而且它們也不在數組中。也許不是,我想在所有的承諾解決之前,不可能真的有一個數組。 –