如何避免回调地狱

5

我在AngularJS中有一个需要两个回调函数确认的对话框:一个是当用户点击“是”,另一个是当用户点击“否”时触发。

我需要先询问用户是否完成了操作,如果用户回答“是”,我还需要问他是否想将该用户添加为管理员。无论两个问题的回答如何,我都需要保存数据。

所以,我有这个可怕、充斥着回调地狱的代码来处理我上面提到的分支:

$scope.promptAndSave = function() {

  // first question
  $scope.confirmation.display("Confirmation", "Did you finish working on this Reference Check?", function() {

    // handles Yes for first question
    $scope.referenceCheck.finished = true;
    var manager_name = $scope.referenceCheck.first_name + " " + $scope.referenceCheck.last_name;
    $scope.confirmation.display("Add new Manager", "Do you want to add <b>" + manager_name + "</b> as a new manager to your database?", function() {

      // handles Yes for second question
      $scope.referenceCheck.add_manager = true;
      $scope.saveReferenceCheck();

    }, function() {

      // handles No for second question
      $scope.saveReferenceCheck();

    });
  }, function() {

    // handles No for first question
    $scope.saveReferenceCheck();

  });
};

这是否可以通过使用承诺来潜在地解决?或者有其他更通用的JS技术更适合此项任务?
我了解AngularJS提供了$q,这有帮助吗?将上面的代码转换为promise后会是什么样子?
编辑
因此,确认是我的$scope上的本地对象,就像这样:
$scope.confirmation = {
  visible: false,
  title: "",
  prompt: "",
  yes: function() {
    this.visible = false;
    this.yesHandler();
  },
  no: function() {
    this.visible = false;
    this.noHandler();
  },
  display: function(title, prompt, yesHandler, noHandler) {
    this.title = title;
    this.prompt = prompt;
    this.yesHandler = yesHandler;
    this.noHandler = noHandler;
    this.visible = true;
  }
};

我有一个与对象交互的模板HTML代码,用于显示提示:

<div id="confirmationForm" ng-show="confirmation.visible">
  <div class="form-title">{{ confirmation.title }}</div>
  <div class="form-body">
    <div class="message" ng-bind-html-unsafe="confirmation.prompt"></div>

    <div class="actions">
      <span>
        <button ng-click="confirmation.yes()">Yes</button>
        <button ng-click="confirmation.no()">No</button>
      </span>
      <img src="/assets/spinner.gif" ng-show="confirmation.busy">
    </div>
  </div>
</div>

编辑2

在得到一些帮助后,我成功地完成了这个项目:http://jsfiddle.net/LJr5z/1/

编辑3

最后,$q不支持Angular 1.0.3中的finally,因此这是最新版本的JSFiddle,使用了AngularJS 1.2 - http://jsfiddle.net/LJr5z/3/


1
是的,Promises 在这里非常完美。你试过它们吗? - Daniel A. White
@DanielA.White 不,我需要了解转换为 Promises 后的样子。你能帮忙吗? - kolrie
什么是“确认”? - Daniel A. White
@DanielA.White 添加了 $scope.confirmation 对象,以及我的模板代码。 - kolrie
1个回答

5

所以注入 $q 并尝试以下操作。

$scope.confirmation = {
  visible: false,
  title: "",
  prompt: "",
  yes: function() {
    this.visible = false;
    this.dfd.resolve();
  },
  no: function() {
    this.visible = false;
    this.dfd.reject();
  },
  display: function(title, prompt) {
    this.dfd = $q.defer();
    this.title = title;
    this.prompt = prompt;
    this.visible = true;
    return this.dfd.promise;
  }
};

要调用它:

$scope.confirmation.display('title', 'prompt')
.then(function() { 
    // return another promise here, yes clicked
}, function() {
    // no clicked
})
.then(...);

我喜欢它,但是我理解现在我需要用不同的名称来调用它,对吗? - kolrie
我想我明白了,让我试试! :) - kolrie
没戏了,我觉得我错过了一些微不足道的东西。这是我到目前为止的进展 - http://jsfiddle.net/LJr5z/1/ - kolrie
我已经解决了问题,并发现问题出在 Angular 1.0.3 的 $q 上,它非常糟糕 - 它甚至不支持 finally。但是我成功地使用 1.2.1 版本解决了这个问题 - 在这里可以查看 http://jsfiddle.net/LJr5z/3/。谢谢! - kolrie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接