【问题标题】:Promises inside a setIntervalsetInterval 中的 Promise
【发布时间】:2016-04-17 17:22:00
【问题描述】:

我有一个 setInterval 每秒运行一个 promise,在每个 promise 的 then 函数中,我将输出放入 MongoDB 数据库(尽管由于某种原因它不起作用)。

我想在一切完成后关闭与数据库的连接,但我不知道如何使连接的关闭仅在所有承诺都完成并且所有内容都完成写入数据库时​​运行。

这是我当前的代码:

我有一个 client.js 文件,用于使用 Promise 向商店发出查询,还有一个 db.js,用于处理 DB 功能。

client.js

var id = setInterval(function(){

        if (i == (categories.length-1))
            clearInterval(id);


            var category = categories[i];

            client.itemSearch({  
              searchIndex: SearchIndex,
              categoryID: category.id,
              keywords: currentKeyword
            })
            .then(function(results){

                var title = results[0].Title;
                var cat = category.name;
                var price = results[0].Price

                db.insertProduct(title,cat,price).then(function(){
                    console.log("Added " + title);
                })
            },function(err) {
                console.log("error at " + category.name);
            });
            i+=1;
    }, 1000)

queryStore();

db.js

var mongoose = require("mongoose");

mongoose.connect('mongodb://localhost:27017/catalog');

var schema = new mongoose.Schema({
    title           : String,
    category        : String,
    price           : Number,
}, {collection: "catalog"});

var Product = mongoose.model("Product", schema);

Product.remove({}, function() {
    console.log('Database cleared.') 
});


exports.clearDB = function() {
    Product.remove({});
}

exports.insertProduct = function (Title,Category,Price) {
    var entry = new Product({
        title: Title,
        category: Category,
        price: Price,
    });

    entry.save();
}

exports.closeConn = function() {
    console.log("Closing DB Connection");
    mongoose.connect().close();
}

另外,由于我对 JavaScript 和 Node.js 完全陌生,任何最佳实践或一般提示都将不胜感激! :)

【问题讨论】:

  • Promise 不是“运行”,它们只是被创建。
  • 我真的建议不要将setInterval 与promise 一起使用。 Promisify setTimeout 并且只使用它。
  • @Bergi 你能详细说明一下吗?我不确定我理解这意味着什么
  • 如果您参考我的第一条评论,那只是关于术语。承诺是价值,而不是可以执行的东西。

标签: javascript node.js mongodb promise setinterval


【解决方案1】:

正如所写,您依靠 1 秒的时间间隔在搜索/插入序列的连续调用之间施加延迟。这从根本上没有错,但它不能保证每一步都在下一步开始之前完成,也不能保证下一步会尽快开始。在每一步,1 秒的延迟可能超过或不足,你并不知道。

幸运的是,promise 提供了一种更好的方法来处理异步问题。

从一个数组开始,可以使用经过充分尝试的reduce 模式(请参阅“The Collection Kerfuffle”here 以强加一个序列:

array.reduce(function(promise, item) {
    return promise.then(function() {
        return doSomethingAsync(item);
    });
}, Promise.resolve());

Promise 是 ES6 的原生 Promise,例如 Bluebird。

对于问题中的代码,doSomethingAsync() 部分扩展为:

categories.reduce(function(promise, category) {
    return promise.then(function() {
        return client.itemSearch({
            'searchIndex': SearchIndex,
            'categoryID': category.id,
            'keywords': currentKeyword
        }).then(function(results) {
            var title = results[0].Title;
            var cat = category.name;
            var price = results[0].Price;
            return db.insertProduct(title, cat, price);
        }).then(function() {
            console.log("Added " + title);
        }).catch(function(err) {
            console.log("error at " + category.name);
        });
    });
}, Promise.resolve());

整个reduction过程返回一个promise,它本身可以返回和/或与其他promise聚合。

【讨论】:

  • 我稍微修改了你的代码,希望你不要介意:)
  • 哇,非常感谢!你链接的那篇文章很棒。但是我有一个问题,为什么在 reduce 函数中你给 Promise.Resolve() 作为初始值?还有,为什么你把 itemsearch 函数包装在一个 Promise 中,为什么不在项目搜索函数上使用 then() 呢?
  • 缩减过程需要一个“starter promise”,以便变量promise 在第一次迭代中是“thenable”。 starter Promise 需要(在某个时候)被解决,以确保归约过程构建的 Promise 链开始结算。虽然在这种模式中,典型的 starter promise 是 ready-resolved(如上),但它可能是一个稍后解决的 promise,以响应一些异步。
  • @Roamer-1888 非常感谢!这是完美的。在不相关的说明中,我如何使整个函数 queryStore() 成为一个承诺?这样当它完全完成时,我可以 then() 它吗?
  • @Roamer-1888 是的,有一个元主题要求 SO 用户帮助删除这些链接:meta.stackoverflow.com/questions/356294/… 这就是我在编辑您的答案时所做的。
猜你喜欢
  • 2020-07-10
  • 2020-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-08
  • 2018-03-26
  • 1970-01-01
相关资源
最近更新 更多