微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript – 循环中的承诺

在下面的代码中,我有一个无限循环,我不知道它为什么会发生.我最好的猜测是因为里面的函数是异步的,循环不等待它,所以循环永远不会停止.解决这个问题的最佳方法是什么?
var generatetoken = function(userId) {
    return new Promise(function(resolve,reject) {
        User.findOne({userId: userId},function(err,user) {
            if (user !== null) {
                var loop = true;
                while (loop) {
                    var token = Common.randomGenerator(20);
                    (function(e) {
                        User.find({tokens: e},result) {
                            if (err) {
                                loop = false;
                                reject('Error querying the database');
                            } else {
                                if (result.length === 0) {
                                    if (user.tokens === undefined) {
                                        user.tokens = [];
                                    }
                                    user.tokens.push(e);
                                    loop = false;
                                    resolve();
                                }
                            }
                        });
                    })(token);
                }
            } else {
                return reject('UserNotFound');
            }
        });
    });
};

函数接收userId(User.findOne()用于查找用户,如果没有具有该id的用户,则拒绝承诺)并为该用户创建唯一的随机令牌(randomGenerator),将其添加用户实体保存在MongoDB中并将其返回给调用者.

(注意有一些向下的投票说这个问题和this one一样,这不是因为我已经在我的代码中有一个闭包但它仍然不起作用.这个问题更多的是关于如何将循环变量绑定到闭包)

解决方法

你是不对的,你不能像你想做的那样循环.

Javascript是单线程的.因此,只要主线程在while(循环)语句中循环,nothing就有机会运行.如果您的主线程本身正在更改循环变量,那么这一切都会好的,但这并不是正在发生的事情.相反,你试图在异步响应中更改循环变量,但由于你的主线程正在循环,所以不能处理异步响应,因此你的循环变量永远不会被改变,因而是一个非生产性的无限循环.

要修复,您必须更改为不同的循环结构.常见的设计模式是创建一个本地函数,其中包含您想要重复的代码.然后,运行异步操作,如果在异步结果处理程序中,您决定要重复操作,则只需从其中再次调用本地函数.因为结果是异步的,所以堆栈已经展开,这在技术上并不是堆栈构建的递归.它只是启动了该函数的另一个迭代.

我对你的代码中的逻辑感到有点困惑(那里有零注释来解释它)所以我不完全确定我是否正确,但这里是一般的想法:

var generatetoken = function(userId) {
    return new Promise(function(resolve,user) {
            function find() {
                var token = Common.randomGenerator(20);
                User.find({tokens: e},result) {
                    if (err) {
                        reject('Error querying the database');
                    } else {
                        if (result.length === 0) {
                            if (user.tokens === undefined) {
                                user.tokens = [];
                            }
                            user.tokens.push(e);
                            resolve();
                        } else {
                            // do another find until we don't find a token
                            find();
                        }
                    }
                });
            }

            if (user !== null) {
                find();
            } else {
                reject('UserNotFound');
            }
        });
    });
};

我应该注意到你在User.findOne()操作上有不完整的错误处理.

仅供参考,持续查询直到你得到result.length === 0的整个逻辑似乎很奇怪.逻辑似乎很奇怪,它闻起来像“在紧密循环中轮询数据库”,这通常是一个非常糟糕的表现.我怀疑如果我们在更高层次上理解整体问题,有更有效的方法解决这个问题.

原文地址:https://www.jb51.cc/js/240662.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐