V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
vainly
V2EX  ›  Node.js

Nodejs 中并发请求在同一个方法中,变量是共享的吗?

  •  
  •   vainly · 2017-06-09 11:02:08 +08:00 · 3256 次点击
    这是一个创建于 2729 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,遇到一个问题,在一个回调方法中多次回调获取的请求尽然是第一次请求的数据,具体请看下文。

    1.Tools.shortId()

    //用来生成 8 位的数字 id
    var redis = new IoRedis(config.redis.dev);
    
    var lock = require("redis-lock")(redis, 50);
    exports.shortid = function (key, retries, callback) {
        var self = this;
    
        if (typeof retries === "function" && !callback) {
            self.cb = retries;
            self.retries = 5;
        } else if (typeof retries === "number") {
            self.retries = retries;
            self.cb = callback;
        } else {
            throw new Error('illegal parameters');
        }
    
    
        //生成 id
        var getId = function () {
            var num = new Array(8);
            var c;
            for (var i = 0; i < 8; i++) {
                num[i] = Math.floor(Math.random() * 9 + (i === 0 ? 1 : 0));
                c = num[i];
                for (var j = 0; j < i; j++) {
                    if (num[j] === c) {
                        i--;
                        break
                    }
                }
            }
            return num.toString().replace(/,/g, '');
        };
    
        var setbit = function (id, callback) {
            redis.setbit('shortid:' + key, id, 1, callback);
        };
    
        var getbit = function (id, callback) {
            redis.getbit('shortid:' + key, id, callback);
        };
    
        var retry = function (cb) {
            //获取锁
            lock('shortidt:lock:' + key, function (done) {
                var id = getId();
                getbit(id, function (err, ret) {
                    if (err) {
                        cb(err, null);
                    } else {
                        if (ret === 0) {
                            setbit(id, function (err, ret) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    done(function () {
                                        cb(null, parseInt(id));
                                    });
                                }
                            });
                        } else {
                            cb(null, null);
                        }
                    }
                });
    
            });
        };
    
        var _num = 0;
        var intervalId = setInterval(function () {
            retry(function (err, id) {
                if (!id) {
                    if (_num === self.retries) {
                        clearInterval(intervalId);
                        self.cb(null, null);
                    } else {
                        _num = _num + 1;
                    }
                } else {
                    clearInterval(intervalId);
                    self.cb(err, id);
                }
            });
        }, 50);
    };
    

    2.module

    //mongoose schema
    var mongoose  = require('mongoose');
    var Schema    = mongoose.Schema;
    
    
    var UserSchema = new Schema({
        loginid: { type: Schema.Types.ObjectId },
        id: { type: Schema.Types.Number },
        loginname: { type: String },
        email: {type: String },
    })
    

    3.proxy

    exports.saveUser = function (data, callback) {
        var user = new User(data);
        
        Tool.shortid(SHORTID_KEY, 10, function (err, id) {
            if(err || !id) {
                console.error("failed to get shortid. > ", err);
                callback(err, id);
            }else{
                user.loginid = new mongoose.Types.ObjectId(id);
                user.id = id;
    
                console.log("email::" + user.email);
                user.save(callback);
            }
        });
    })
    
    

    在同时处理多个请求时,发现输出的 email 结果总是第一个请求的 email 数据值。不知为何,还请各位帮忙解惑

    5 条回复    2017-06-09 14:09:47 +08:00
    vainly
        1
    vainly  
    OP
       2017-06-09 12:54:41 +08:00
    /**
    * Created by chaclus on 2017/6/9.
    */

    var IoRedis = require('ioredis');
    var redis = new IoRedis(dev: {
    host: '127.0.0.1',
    port: 6379,
    password: 'root'
    });

    var lock = require("redis-lock")(redis, 50);
    var shortid = function (key, retries, callback) {
    var self = this;

    if (typeof retries === "function" && !callback) {
    self.cb = retries;
    self.retries = 5;
    } else if (typeof retries === "number") {
    self.retries = retries;
    self.cb = callback;
    } else {
    throw new Error('illegal parameters');
    }


    //生成 id
    var getId = function () {
    var num = new Array(8);
    var c;
    for (var i = 0; i < 8; i++) {
    num[i] = Math.floor(Math.random() * 9 + (i === 0 ? 1 : 0));
    c = num[i];
    for (var j = 0; j < i; j++) {
    if (num[j] === c) {
    i--;
    break
    }
    }
    }
    return num.toString().replace(/,/g, '');
    };

    var setbit = function (id, callback) {
    redis.setbit('shortid:' + key, id, 1, callback);
    };

    var getbit = function (id, callback) {
    redis.getbit('shortid:' + key, id, callback);
    };

    var retry = function (cb) {
    //获取锁
    lock('app:shortidt:lock:' + key, function (done) {
    var id = getId();
    getbit(id, function (err, ret) {
    if (err) {
    cb(err, null);
    } else {
    if (ret === 0) {
    setbit(id, function (err, ret) {
    if (err) {
    cb(err, null);
    } else {
    done(function () {
    cb(null, parseInt(id));
    });
    }
    });
    } else {
    cb(null, null);
    }
    }
    });

    });
    };

    var _num = 0;
    var intervalId = setInterval(function () {
    retry(function (err, id) {
    if (!id) {
    if (_num === self.retries) {
    clearInterval(intervalId);
    self.cb(null, null);
    } else {
    _num = _num + 1;
    }
    } else {
    clearInterval(intervalId);
    self.cb(err, id);
    }
    });
    }, 50);
    };

    var save = function (data) {

    shortid('user', 10, function (err, id) {
    if(err) {
    console.error("err:", err);
    }else{
    console.log("id: "+ id+", email: " + data.email)
    }
    });
    };


    var user = ['a', 'b', 'c', 'd', 'e', 'f'];

    user.forEach(function (user) {
    save({name: user, email: user + "@gmail.com"});
    });

    这个填写 redis 可以直接调试。
    oott123
        2
    oott123  
       2017-06-09 13:18:20 +08:00   ❤️ 1
    我看你上来就 var self = this, 你有想过你这个地方 this === global 吗?
    oott123
        3
    oott123  
       2017-06-09 13:26:21 +08:00   ❤️ 1
    有个简单的方法是改成 var self = {}; 试试。。。
    vainly
        4
    vainly  
    OP
       2017-06-09 14:03:42 +08:00
    @oott123 兄台,请收下我的膝盖,一语点醒梦中人。
    vainly
        5
    vainly  
    OP
       2017-06-09 14:09:47 +08:00
    @oott123 谢谢你
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1043 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 21:49 · PVG 05:49 · LAX 13:49 · JFK 16:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.