承诺链接和处理不返回承诺链中任何内容的操作

bal*_*teo 5 angularjs angular-promise

我有一个关于 Javascript 承诺链的问题。假设我在承诺链的某个地方有一个行动。该操作不会返回任何值,但必须在链继续之前完成。

我需要将这个行动包含在一个承诺中吗?我需要这样的东西吗:

$q.when();
Run Code Online (Sandbox Code Playgroud)

请参阅下面我的代码:

...
var goToDashboard = function () {
    //TODO: use $q here?
    $state.go('dashboard');
};
...
activateEmail().then(signinByToken).then(setPersonalInfo).then(goToDashboard).then(somethingElse).catch(reportProblem);
Run Code Online (Sandbox Code Playgroud)

有人可以建议吗?

JcT*_*JcT 3

在下面,我.then使用来自各种函数和其他返回类型的 Promise 演示了链接。当然,如果不返回 Promise,就不会出现延迟解析,并且以下内容.then会立即执行 - 因此,如果您有需要完成的异步任务,则需要返回一个在异步任务完成时解析的 Promise。请注意,返回确实$q.when()会返回一个承诺(包含您作为参数提供的任何内容),但它会立即得到解决。

另外,请注意,$state.go实际上返回的是一个承诺!因此,在上面的示例中,您可以在 ui-router 更改路由之前执行return $state.go('dashboard');以下操作(如下所示)。.then

(function() {
  "use strict";

  angular.module('myApp', ['ui.router', 'ngResource'])
    .controller('myController', ['$scope', '$state', '$q', '$timeout', '$resource', '$log', MyController])
    .config(['$stateProvider', configUiRouter]);

  function configUiRouter($stateProvider) {
    $stateProvider
      .state("home", {
        url: "/home",
        template: "<div>Home state</div>"
      })
      .state("dashboard", {
        url: "/dashboard",
        template: "<div>Dashboard state</div>"
      })
      .state("error", {
        url: "/error",
        template: "<div>Error state: I'm sorry Dave, I'm afraid I can't do that...</div>"
      });
  }

  function MyController($scope, $state, $q, $timeout, $resource, $log) {

    $scope.status = {
      emailActivated: false,
      signinByToken: false,
      personalInfo: false,
      stackoverflowUsers: null,
      loading: null,
      counter: 0
    };

    $state.go('home'); // set default state for ui-router test

    activateEmail()
      .then(updateStatusLoading).then(counting) // Loading: . Counter: 1
      .then(signinByToken)
      .then(updateStatusLoading).then(counting) // Loading: .. Counter: 2
      .then(setPersonalInfo)
      .then(updateStatusLoading).then(counting) // Loading: ... Counter: 3
      .then(goToDashboard)
      .then(updateStatusLoading).then(counting) // Loading: .... Counter: 4
      .then(somethingElse)
      .then(triggerError)
      .then(neverReached)
      .catch(catchesReject);


    /* * * * * * * * * * *
     * Promise functions *
     * * * * * * * * * * */

    // doesn't return any promise
    // (resolves immediately)
    function updateStatusLoading() {
      if (!$scope.status.loading) {
        $scope.status.loading = "";
      }
      $scope.status.loading += ".";
    }

    // returns something other than a promise (a String...)
    // (resolves immediately)
    function counting() {
      $scope.status.counter++;
      return "Did some counting... (" + $scope.status.counter + ")";
    }

    // using promise returned by $timeout
    // (delayed resolution)
    function activateEmail() {
      return $timeout(function simulateActivateEmailLatency() {
        $scope.status.emailActivated = true;
      }, 1000);
    }

    // using promise returned by $q.defer, resolved in a $timeout
    // (the return is immediate, but the resolve is delayed)
    function signinByToken() {
      var deferred = $q.defer();

      $timeout(function simulateSignInLatency() {
        $scope.status.signinByToken = true;
        deferred.resolve({
          returningSomething: "Is entirely optional"
        });
      }, 1000);

      //log to console what this object looks like
      $log.log("deferred.promise: ", deferred.promise);

      return deferred.promise;
    }

    // using promise created by $q.when; no timeout
    // (immediate resolution)
    function setPersonalInfo() {
      $scope.status.personalInfo = true;

      $log.log("$q.when: ", $q.when({
        foo: "bar"
      }));

      return $q.when({
        returningSomething: "Is entirely optional"
      });
    }

    // using promise created by $state.go
    // (will resolve once route has changed; which could include time spent doing ui-router resolves...)
    function goToDashboard() {
      // yup, this returns a promise!
      // https://github.com/angular-ui/ui-router/wiki/Quick-Reference#stategoto--toparams--options
      var goPromise = $state.go('dashboard');

      $log.log("$state.go: ", goPromise);

      return goPromise;
    }

    // using $promise returned by resource, and adding an .then
    // (resolves when the $resource does)
    function somethingElse() {
      var resourceContainingPromise = $resource('https://api.stackexchange.com/2.2/info')
        .get({
          site: 'stackoverflow'
        });

      // (note that it contains a $promise, is not a promise itself)
      $log.log("$resource: ", resourceContainingPromise);

      return resourceContainingPromise
        .$promise
        .then(function resourceHandler(results) {
          $scope.status.stackoverflowUsers = results.items[0].total_users;
        });
    }

    // returns a rejected promise
    // (immediate resolve)
    function triggerError() {
      var rejectPromise = $q.reject("An error message");

      $log.log("$q.reject: ", rejectPromise);

      return rejectPromise;
    }

    // this gets skipped due to .triggerError()
    function neverReached() {

      $log.error("Shouldn't see this!");

      $scope.status.loading += "Never reached!";
    }

    // this catches the $q.reject and logs the data it passed...
    function catchesReject(data) {
      $log.log(data); //log the error message
      return $state.go('error');
    }

  }
})();
Run Code Online (Sandbox Code Playgroud)
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular-resource.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.14/angular-ui-router.min.js"></script>
<div ng-app="myApp">
  <div ng-controller="myController">
    <div style="display:inline-block; float:left; margin-right: 20px; min-width: 250px;">
      <ul>
        <li>Email activated: {{status.emailActivated}}</li>
        <li>Sign-in by Token: {{status.signinByToken}}</li>
        <li>Personal info set: {{status.personalInfo}}</li>
        <li>Stackoverflow Users: {{status.stackoverflowUsers}}</li>
      </ul>
      <hr />
      Loading: {{status.loading}}
      <br />Counter: {{status.counter}}
    </div>
    <div style="display:inline-block; padding: 10px; border: 1px solid grey; max-width: 150px;">
      <strong>Ui Router Test</strong>
      <div ui-view></div>
    </div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)