2015-01-07 1 views
0

У меня есть поток baconjs, который я использую для сохранения статей с помощью mongoose. Вот код:Как выйти из nodejs в конце потока, поэтому последние значения сохраняются в db и правильно регистрируются

function main() { 
    db.once('open', function(callback) { 
    console.log('db connection successs'); 
    console.log('stremaing page ' + page); 

    var stream = readSite(page); 
    stream.onValue(function(article) { 
     try { 
     article = toArticleModel(article); 
     } catch (e) { 
     console.error(e); 
     } 
     article.save(function(err, article) { 
     if (err) { 
      console.error('Save Error: ' + err); 
     } else { 
      console.log('saved ' + article.publishedDate + " " + article.author.name + " " + article.title); 
     } 
     }); 

     stream.onError(function(err) { 
     console.error('Stream Error: ' + err); 
     }); 

     stream.onEnd(function() { 
     console.log('stream ended closing in 15 seconds..'); 
     setTimeout(function() { 
      db.close(); 
     }, 15 * 1000); 
     }); 
    }); 
}); 

После того, как поток заканчивается onEnd, я хочу, чтобы закрыть соединение с базой данных и выхода из программы nodejs. Я понял, как только поток закончится, я должен подождать некоторое время, чтобы последние значения были сохранены в db. Поэтому я использую setTimeout в течение 15 секунд и использую db.close.

Проблема в том, что журнал stream ended closing in 15 seconds.. зарегистрирован 50-60 раз в стандартном режиме, почему? И это хороший подход к выходу из такой программы?

ответ

1

Вы добавляете stream.onEnd слушателя внутриstream.onValue. Это означает, что вы добавляете слушателя каждый раз, когда запускается onValue. Вам нужно добавить слушателей событий за пределы других прослушивателей событий, чтобы они были добавлены только один раз.

Существует множество методов обработки асинхронной итерации, чтобы убедиться, что все значения значений сохраняются до закрытия БД (шаг, на котором вы, возможно, сможете уйти просто с пропуском).

// initialize savingArticles to 0 

savingArticles++; 
article.save(function (err, article) { 
    savingArticles-- 
    if (streamEnded && !savingArticles) 
    db.close(); 

stream.onEnd(function() { 
    if (!savingArticles) 
    db.close(); 
    else 
    streamEnded = true; 

Это закроет БД, если статья в настоящее время не сохраняется и поток закончился. Если поток заканчивается во время сохранения статьи, тогда БД следует закрыть после сохранения этой статьи.

+1

Использование изменяемых состояний (переменные 'savingArticles',' streamEnded') является признак плохого кода при использовании FRP. Использование 'flatMap' и' fromNodeCallback' в ответе Романа Поминова намного лучше. – OlliM

1

Я хотел бы попробовать использовать .fromNodeCallback и .flatMap для этого:

stream = stream.flatMap(function(article) { 

    try { 
    article = toArticleModel(article); 
    } catch (e) { 
    return new Bacon.Error('toArticleModel error: ' + err); 
    } 

    return Bacon.fromNodeCallback(function(callback) { 
    article.save(function(err, article) { 
     if (err) { 
     callback('Save Error: ' + err); 
     } else { 
     callback('saved ' + article.publishedDate + " " + article.author.name + " " + article.title); 
     } 
    }); 
    }); 

}); 

stream.onError(console.error.bind(console)); 
stream.onValue(console.log.bind(console)); 
stream.onEnd(db.close.bind(db)); 

Она также может быть упрощена дальше:

stream = stream.flatMap(function(article) { 

    try { 
    article = toArticleModel(article); 
    } catch (e) { 
    return new Bacon.Error(err); 
    } 

    return Bacon.fromNodeCallback(article, "save") 
    .map(function() { 
     return "saved " + article.publishedDate + " " + 
     article.author.name + " " + article.title; 
    }); 

}); 

stream.log(); 
stream.onEnd(db.close.bind(db));