淘汰赛中的比赛条件

时间:2018-02-09 19:10:15

标签: javascript knockout.js race-condition

我最近在我的代码中遇到了一个关于竞争条件的小问题。我正在使用Knockout.Js收集一些信息以显示给用户。

在可以选择值之前需要生成下拉列表时会发生故障。 通常下拉列表小于其他请求并将赢得比赛,因此不会造成任何问题。但是我在我的应用程序中看到了一些情况,在较慢的Internet连接上,列表第二次加载。以下是一个例子。如果列表中没有该值的选项,则无法选择该选项,并且对用户显示似乎没有选择一个选项。

使用setTimeout我模拟了这种体验。您可以交换这两个值以查看"成功"场景。



function ViewModel() {
  var self = this;

  self.UserName = ko.observable();
  self.UserGroup = ko.observable();
  self.GroupList = ko.observableArray();

  self.LoadUserGroups = function() {
    //Ajax call to populate user groups 

    setTimeout(function() {
      response = "Red Team,Blue Team,Green Team".split(",");

      self.GroupList(response)
    }, 2000) /// SWAP ME 
  }

  self.LoadUserInformation = function() {
    setTimeout(function() {
      response = {
        UserName: "John Pavek",
        UserGroup: "Blue Team"
      };

      self.UserName(response.UserName);
      self.UserGroup(response.UserGroup);

    }, 1000) // SWAP ME
  }

  self.Load = function() {
    self.LoadUserGroups();
    self.LoadUserInformation();
  }

  self.Load();

}

ko.applyBindings(new ViewModel())

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

User Name:
<input data-bind="value: UserName" /> User Group:
<select data-bind="options: GroupList, optionsCaption: '--Pick a Team--', value: UserGroup"></select>
&#13;
&#13;
&#13;

我可以在我的代码,Vanilla或淘汰赛中添加什么来防止此问题发生而不会减慢整个体验?

2 个答案:

答案 0 :(得分:2)

UserGroup尝试设置的值不在选项列表中时,选项覆盖LoadUserInformation会发生什么。但您可以使用valueAllowUnset告诉它不要担心未知值。然后它不会覆盖。

function ViewModel() {
  var self = this;

  self.UserName = ko.observable();
  self.UserGroup = ko.observable();
  self.GroupList = ko.observableArray();

  self.LoadUserGroups = function() {
    //Ajax call to populate user groups 

    setTimeout(function() {
      response = "Red Team,Blue Team,Green Team".split(",");

      self.GroupList(response)
    }, 2000) /// SWAP ME 
  }

  self.LoadUserInformation = function() {
    setTimeout(function() {
      response = {
        UserName: "John Pavek",
        UserGroup: "Blue Team"
      };

      self.UserName(response.UserName);
      self.UserGroup(response.UserGroup);

    }, 1000) // SWAP ME
  }

  self.Load = function() {
    self.LoadUserGroups();
    self.LoadUserInformation();
  }

  self.Load();

}

ko.applyBindings(new ViewModel())
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

User Name:
<input data-bind="value: UserName" /> User Group:
<select data-bind="options: GroupList, optionsCaption: '--Pick a Team--', value: UserGroup, valueAllowUnset: true"></select>

答案 1 :(得分:1)

除了LoadUserInformation之前 从<{1}}获取信息之后,我们别无选择。但这根本不会减慢经验。

您需要将加载与显示信息的分开。在非承诺环境中,我让每个函数都接受回调,然后只有在我得到两个结果时才进行(调用&#34; show&#34;函数),请参阅LoadUserGroups注释:< / p>

&#13;
&#13;
***
&#13;
function ViewModel() {
  var self = this;

  self.UserName = ko.observable();
  self.UserGroup = ko.observable();
  self.GroupList = ko.observableArray();

  // *** Only loads, doesn't show
  self.LoadUserGroups = function(callback) {
    //Ajax call to populate user groups 

    setTimeout(function() {
      callback("Red Team,Blue Team,Green Team".split(","));
    }, 2000);
  }
  
  // *** Shows
  self.ShowUserGroups = function(groups) {
      self.GroupList(groups);
  };

  // *** Only loads, doesn't show
  self.LoadUserInformation = function(callback) {
    setTimeout(function() {
      callback({
        UserName: "John Pavek",
        UserGroup: "Blue Team"
      });
    }, 1000);
  };
  
  // *** Shows
  self.ShowUserInformation = function(info) {
      self.UserName(info.UserName);
      self.UserGroup(info.UserGroup);
  };

  self.Load = function() {
    var groups = null, userInfo = null;
    self.LoadUserGroups(function(g) {
      groups = g;
      checkDone();
    });
    self.LoadUserInformation(function(u) {
      userInfo = u;
      checkDone();
    });
    function checkDone() {
      if (groups && userInfo) {
        // *** We have both, show them
        self.ShowUserGroups(groups);
        self.ShowUserInformation(userInfo);
      }
    }
  }

  self.Load();

}

ko.applyBindings(new ViewModel())
&#13;
&#13;
&#13;

从技术上讲,当然,如果他们在用户信息之前到达,则不会阻止您显示这些组,您只需使用状态标记:

&#13;
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

User Name:
<input data-bind="value: UserName" /> User Group:
<select data-bind="options: GroupList, optionsCaption: '--Pick a Team--', value: UserGroup"></select>
&#13;
function ViewModel() {
  var self = this;

  self.UserName = ko.observable();
  self.UserGroup = ko.observable();
  self.GroupList = ko.observableArray();

  // *** Only loads, doesn't show
  self.LoadUserGroups = function(callback) {
    //Ajax call to populate user groups 

    setTimeout(function() {
      callback("Red Team,Blue Team,Green Team".split(","));
    }, 2000);
  }
  
  // *** Shows
  self.ShowUserGroups = function(groups) {
      self.GroupList(groups);
  };

  // *** Only loads, doesn't show
  self.LoadUserInformation = function(callback) {
    setTimeout(function() {
      callback({
        UserName: "John Pavek",
        UserGroup: "Blue Team"
      });
    }, 1000);
  };
  
  // *** Shows
  self.ShowUserInformation = function(info) {
      self.UserName(info.UserName);
      self.UserGroup(info.UserGroup);
  };

  self.Load = function() {
    var haveGroups = false, userInfo = null;
    self.LoadUserGroups(function(groups) {
      // *** No need to wait for the user info
      self.ShowUserGroups(groups);
      haveGroups = true;
      checkDone();
    });
    self.LoadUserInformation(function(u) {
      userInfo = u;
      checkDone();
    });
    function checkDone() {
      if (haveGroups && userInfo) {
        // *** Show the user info
        self.ShowUserInformation(userInfo);
      }
    }
  }

  self.Load();

}

ko.applyBindings(new ViewModel())
&#13;
&#13;
&#13;

在承诺环境中,我有#34;加载&#34;函数返回promises,然后使用它们看起来像这样而不需要<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> User Name: <input data-bind="value: UserName" /> User Group: <select data-bind="options: GroupList, optionsCaption: '--Pick a Team--', value: UserGroup"></select>调用:

checkDone

......使用ES2015 +参数解构语法变得更清晰:

Promise.all([
    self.LoadUserGroups().then(self.ShowUserGroups),
    self.LoadUserInfo()
]).then(function(results) {
    self.ShowUserInfo(results[1]);
});