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

2017-06-09 11:02:08 +08:00
 vainly

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

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 数据值。不知为何,还请各位帮忙解惑

3170 次点击
所在节点    Node.js
5 条回复
vainly
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
2017-06-09 13:18:20 +08:00
我看你上来就 var self = this, 你有想过你这个地方 this === global 吗?
oott123
2017-06-09 13:26:21 +08:00
有个简单的方法是改成 var self = {}; 试试。。。
vainly
2017-06-09 14:03:42 +08:00
@oott123 兄台,请收下我的膝盖,一语点醒梦中人。
vainly
2017-06-09 14:09:47 +08:00
@oott123 谢谢你

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/367160

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX