Javascript 从客户端调用node.js服务时的竞争条件

Javascript 从客户端调用node.js服务时的竞争条件,javascript,node.js,asynchronous,Javascript,Node.js,Asynchronous,我有两个节点服务调用:一个用于从LDAP组获取组成员,另一个用于获取每个成员的详细信息。每个调用都是非阻塞的回调,因此我遇到了这样的情况:有时我所使用的记录与为个人检索的详细信息不匹配 有没有一种聪明的方法来编写代码以防止竞争状况?有时它可以工作,但通常在我在下面的控制台日志行中,我迭代的记录与从商店返回的记录不匹配,无法获取员工详细信息。下面是代码: onGroupSelected: function (list, idx, el, record) { var store = Ext.

我有两个节点服务调用:一个用于从LDAP组获取组成员,另一个用于获取每个成员的详细信息。每个调用都是非阻塞的回调,因此我遇到了这样的情况:有时我所使用的记录与为个人检索的详细信息不匹配

有没有一种聪明的方法来编写代码以防止竞争状况?有时它可以工作,但通常在我在下面的控制台日志行中,我迭代的记录与从商店返回的记录不匹配,无法获取员工详细信息。下面是代码:

onGroupSelected: function (list, idx, el, record) {
    var store = Ext.getStore('GroupMembers');
    store.getProxy().setUrl('http://people-nodejs.xxx.xxx.com/ldap/group/' + record.get('cn'));
    var that = this;
    store.load({
        callback: function (records, operation) {
            var empstore = Ext.getStore('EmployeeDetails');
            Ext.each(records, function(rec, ndx) {
                console.log(ndx + ":" + rec.get('memberUid'));
                if (rec.get('isMember')) {
                    empstore.getProxy().setUrl('http://people-nodejs.xxx.xxx.com/ldap/user/' + rec.get('memberUid'));
                    empstore.load({
                        callback: function(emps, op) {
                            console.log(ndx + ":" + rec.get('memberUid') + "--" + emps[0].get('fullName'));
                            rec.set('workforceID', emps[0].get('workforceID'));
                            rec.set('fullName', emps[0].get('fullName'));
                            that.getGroupMembersList().setRecord(rec);
                        }
                    });
                }
            });
            // Remove empty records and populate with records from above
            store.removeAll();
        }
    });

在单线程环境中,如Javascript和node.js,您不能真正拥有竞争条件

相反,您会遇到javascript闭包,并对变量如何在嵌套函数和循环中工作产生误解

rec是在Ext.eachrecords、functionrec、ndx中定义的,在回调函数中,您正在使用它的值,假设在每次迭代中,rec在执行回调时仍然绑定到相同的值

这是不正确的,相反,rec的值是在执行回调函数时绑定的,而不是在创建函数时绑定的,这本质上是闭包的定义

因此,要使其按预期方式工作,您需要在创建过程中强制绑定rec,方法是执行类似于“注意:语法可能有问题”:

callback: (function(myrec,index){ 
    return function(emps, op) {
      console.log(index + ":" + myrec.get('memberUid') + "--" + emps[0].get('fullName'));
      myrec.set('workforceID', emps[0].get('workforceID'));
      myrec.set('fullName', emps[0].get('fullName'));
      that.getGroupMembersList().setRecord(myrec);
    };)(rec,ndx);

在上面的示例中,我们立即执行一个匿名javascript函数,传入值rec,该值在创建时由myrec绑定。匿名函数返回一个具有回调所需签名的函数,当回调执行该函数时,它将具有rec的正确值。在单线程环境中,如Javascript和node.js,您不能真正具有竞争条件

相反,您会遇到javascript闭包,并对变量如何在嵌套函数和循环中工作产生误解

rec是在Ext.eachrecords、functionrec、ndx中定义的,在回调函数中,您正在使用它的值,假设在每次迭代中,rec在执行回调时仍然绑定到相同的值

这是不正确的,相反,rec的值是在执行回调函数时绑定的,而不是在创建函数时绑定的,这本质上是闭包的定义

因此,要使其按预期方式工作,您需要在创建过程中强制绑定rec,方法是执行类似于“注意:语法可能有问题”:

callback: (function(myrec,index){ 
    return function(emps, op) {
      console.log(index + ":" + myrec.get('memberUid') + "--" + emps[0].get('fullName'));
      myrec.set('workforceID', emps[0].get('workforceID'));
      myrec.set('fullName', emps[0].get('fullName'));
      that.getGroupMembersList().setRecord(myrec);
    };)(rec,ndx);

在上面的示例中,我们立即执行一个匿名javascript函数,传入值rec,该值在创建时由myrec绑定。匿名函数返回一个具有回调所需签名的函数,当回调执行该函数时,它将具有适当的rec值

浏览器客户端不是单线程的,因为它同时调用node.js服务以获取emps详细信息。你提出了一个很好的观点;但是,即使更正了闭包,此更改仍然会产生重复用户的相同结果:客户机对服务器的每次调用都应该由节点独立完成,就像是在自己的线程上执行一样,除非您在处理程序中使用全局变量。如果您看到对服务器api的多个调用导致的问题,那么我怀疑您在调用堆栈的更高位置有另一个与闭包相关的问题,可能是在调用onGroupSelected的代码中,或者可能是以下代码:var empstore=Ext.getStore'EmployeeDetails';Javascript的事件队列将同步执行,直到它等待进一步的IO并被放回事件队列。因此,empstore很可能装载了同一用户两次。对此,我将使用双重检查解决方案。基本上,在加载之前,看看empstore是否已经包含了您试图加载的记录。我已经查找了堆栈,没有其他回调。empstore一次只能包含一条记录,它搜索前一个存储中的每个员工-组成员,因此我所做的是将这一点功能分离到一个单独的函数中,并检查emps.uid===myrec.uid。如果没有,我将进行递归调用以重试。我知道这很难看,但node的速度太快了,你甚至从UI上都看不出来。目前我无法找到更好的解决方案。浏览器客户端不是单线程的,因为它同时调用node.js服务获取emps详细信息。你提出了一个很好的观点;但是,即使更正了闭包,此更改仍然会产生重复用户的相同结果:客户机对服务器的每次调用都应该由节点独立完成,就像是在自己的线程上执行一样,除非您使用全局变量
在你的处理程序中。如果您看到对服务器api的多个调用导致的问题,那么我怀疑您在调用堆栈的更高位置有另一个与闭包相关的问题,可能是在调用onGroupSelected的代码中,或者可能是以下代码:var empstore=Ext.getStore'EmployeeDetails';Javascript的事件队列将同步执行,直到它等待进一步的IO并被放回事件队列。因此,empstore很可能装载了同一用户两次。对此,我将使用双重检查解决方案。基本上,在加载之前,看看empstore是否已经包含了您试图加载的记录。我已经查找了堆栈,没有其他回调。empstore一次只能包含一条记录,它搜索前一个存储中的每个员工-组成员,因此我所做的是将这一点功能分离到一个单独的函数中,并检查emps.uid===myrec.uid。如果没有,我将进行递归调用以重试。我知道这很难看,但node的速度太快了,你甚至从UI上都看不出来。目前我找不到更好的解决办法。