【问题标题】:Javascript Promise prematurely resolvingJavascript Promise 过早解决
【发布时间】:2017-05-08 15:00:59
【问题描述】:

我有一个返回 Promise 的函数,它访问数据库并拉出几行,将它们分配给 Javascript 变量。

问题是我的 '.then' 子句被触发,即使我知道 Promise 尚未解决:

app.post("/api/hashtag", function (req, res) {

FindPopularRumours().then(function (resolveVar) {
    console.log(resolveVar);
    console.log();
    res.send(resolveVar);
}).catch(function () {
    console.log("DB Error!");
    res.send("DB Error!");
});
});

还有 Promise 函数:

function FindPopularRumours() {
return new Promise((resolve, reject) => {
    var hashtags = [];
    var dbPromise;

    db.collection(HASHTAGS).find().forEach(function (doc) {
        hashtags.push(doc.hashtag);
        console.log(hashtags);
    });
    resolve(hashtags);
});
}

结果输出为:

[ ]

['#test1']

['#test1', '#test2']

['#test1', '#test2', '#test3']

如您所见,第一行 ('[ ]') 仅应在主题标签输出后执行。但由于某种原因,我的代码似乎认为 Promise 在实际解决之前就已经解决了。

编辑1

根据 Ankit 的建议,我将函数修改为:

function FindPopularRumours() {
return new Promise((resolve, reject) => {
    var hashtags = [];

    db.collection(HASHTAGS).find({}, function (err, doc) {
        if (!err) {
            doc.forEach(function (arg) {
                hashtags.push(arg.hashtag);
                console.log(hashtags);
            });
            resolve(hashtags);
        } else {
            return reject(err);
        }
    });
});
}

这仍然返回与以前相同的输出响应(例如,'then' 子句在承诺本身之前运行)。

我的POST功能还是和以前一样。

【问题讨论】:

  • 当然,因为你确实在加载数据之前解决了承诺。 db.collection(HASHTAGS).find() 是异步的。

标签: javascript mongodb promise


【解决方案1】:

db.collection.find() 函数是异步的,所以你必须在 inside 的回调中解决 promise,类似于

function FindPopularRumours() {
    return db.collection(HASHTAGS).find().toArray().then( (items) => {
        return items.map( doc => doc.hashtag);
    });
}

利用 Mongo toArray() 方法,直接返回一个承诺

【讨论】:

  • 您好,感谢您的回复。更改为您的建议后,控制台输出现在是:Promise { <pending> } 这是我这样做的时间:console.log(FindPopularRumours()); 我以前没有看到此待处理消息,但我猜 db find 没有以某种方式解决..?跨度>
  • 呃,那是因为那个函数正在返回一个promise,你不应该这样做FindPopularRumours().then(function (resolveVar) {...
【解决方案2】:

请注意db.collection(HASHTAGS).find() 是一个异步调用。因此,您的承诺在数据库查询返回之前得到解决。为了解决这个问题,你需要重写你的数据库查询如下:

function FindPopularRumours() {
    return new Promise((resolve, reject) => {
       var hashtags = [];
       var dbPromise;

       db.collection(HASHTAGS).find({}, function(err, doc){
           if(!err){
              doc.forEach(function (arg) {
                  hashtags.push(arg.hashtag);
                  console.log(hashtags);
              });
              resolve(hashtags);
           }else{
               return reject(err);
           }
       });
   });
}

希望答案对你有所帮助!

【讨论】:

  • 您好,感谢您的回复!我已经修改了我的代码以匹配您的代码,但仍然有同样的问题。我猜它仍然执行 resolve() 太快(正如你提到的,因为它是异步的)。我尝试做出一系列承诺,并且只有在所有承诺都实现时才会触发我的响应,但这也不起作用。
  • 这真的很奇怪!我不明白为什么它不起作用。您可以更新您的问题并发布您修改后的代码吗?
  • doc.forEach本质上是异步的,因此resolve(hashtags)首先被执行。要解决此问题,请使用 doc.toArray 并在 toArray 的回调中调用 resolve。
  • 感谢您的帮助(@nurulnabi 也是)。 toArray 有效。我已经修改了原始帖子以显示解决方案。
  • @nurulnabi forEach() 是一个阻塞调用。您可以检查此thread 进行验证。我不确定这里出了什么问题。
猜你喜欢
  • 1970-01-01
  • 2018-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多