Promise执行链

Promise执行链

  • 由于javascript的非阻塞式的特性,使得很多写惯阻塞式程序的人在刚开始接触原生js时,显得很难适应,本篇文章就为大家解惑Promise执行链。

首先promise对象的出现,是专门为异步代码同步化所设计的。

  • 抛开promise,仅用callback函数进行处理,显得捉襟见肘。

注:代码使用angular js框架,与其他原生js,例如nodejs原理相同。

.controller('appCtrl', function($timeout, $scope){
    function add(x, y, callback, errorCallback) {
      $timeout(function() {
        callback(x + y)
      }, 100);
    }

    var startTime = Date.now();
    add(5, 2, function(result) {
      add(result, 1, function(result) {
        add(result, 3, function(result) {
          $scope.result = result;
          $scope.elapsedTime = Date.now() - startTime;
        }, function(error){ /* handle error */ })
      }, function(error){ /* handle error */ })
    }, function(error){ /* handle error */ });
  })

陷入无穷无尽的callback调用之中。。。


虽然最初使用promise会显得不适应,但是对于代码本身来说,还是比callback条理性更强。

下面的代码使用了q.defer() 来生成promise结构,与nodejs当中的q 使用类似。

.controller('appCtrl', function($q, $scope){
    function add(x, y) {
      var q = $q.defer();
      setTimeout(function() {
        var result = x + y;
        if (result >= 0) {
          q.resolve(result);
        } else {
          q.reject("negative value: " + result);
        }
      }, 100);
      return q.promise;
    }

    var startTime = Date.now();
    add(5, 2)
      .then(function(result) {
        // 1
        #1 --> return add(result, -10);
        #2 --> return add(result, 3);
      })
      .then(function(result) {
        // 2
        return add(result, 1);
      })
      .then(function(result) {
        // 3
        $scope.result = result;
      })
      .catch(function(failure) {
        // 4
        $scope.failure = failure;
      })
      .finally(function() {
        // 5
        $scope.elapsedTime = Date.now() - startTime;
      })
  })

在链中使用#1 — return add(result, -10);
会使得add函数,reject出一条异常错误。所以promise链的执行顺序为: 1 –> 4 –> 5 。
我们可以看到promise的catch机制,可以捕捉上面链中的任意一个异常。

使用#2 — return add(result, 3);
promise链正常执行,顺序为:1 –> 2 –> 3 –> 5

但是,我们有时希望不经过统一的catch处理,而是在每一个子链当中进行异常处理,这时只需要在链中定义第二个回调函数即可。

var startTime = Date.now();
    add(5, 2)
      .then(function(result) {
        // 1
        return add(result, -10);
      })
      .then(function(result) {
        // 2.1
        return add(result, 1);
      }, function(error) {
        // 2.2
        return add(result, 0);
      })
      .then(function(result) {
        // 3
        $scope.result = result;
      })
      .catch(function(failure) {
        // 4
        $scope.failure = failure;
      })
      .finally(function() {
        // 5
        $scope.elapsedTime = Date.now() - startTime;
      })

我们可以看到在//1 步骤中reject的异常,被//2 步骤中第二个异常回调函数(2.2)捕捉。
具体执行顺序为:1 –> 2.2 –> 3 –> 5

### Promise 的用法及 `.catch` 方法的处理方式 #### ### 1. 基本概念 Promise 是一种用于处理异步操作的对象,表示一个异步操作的最终完成(或失败)及其结果值。通过式调用 `.then()` 和 `.catch()` 方法,可以更清晰地管理和处理异步流程的结果和可能发生的错误[^1]。 --- #### ### 2. `.catch` 方法的作用 `.catch` 方法专门用于捕获 Promise 中任何阶段可能出现的错误。无论是由于显式的 `reject` 还是因为某个 `.then` 回调函数内部抛出了异常,`.catch` 都能捕获并处理这些错误[^3]。 ```javascript new Promise((resolve, reject) => { resolve("Initial value"); }) .then(value => { console.log(value); // 输出 Initial value throw new Error("An error occurred in the first .then"); // 故意引发错误 }) .then(() => { console.log("This will not run because of the previous error."); }) .catch(error => { console.error(`Error captured: ${error.message}`); // 捕获前面的错误 }); ``` 在上面的例子中,第一个 `.then` 抛出的错误被后续的 `.catch` 成功捕获,并打印了相应的错误信息。 --- #### ### 3. 错误传播机制 在一个完整的 Promise 中,一旦某一步发生错误,整个条会跳过剩余的 `.then` 并直接进入最近的一个 `.catch`。这种行为简化了错误处理逻辑,使开发者无需在每一步都单独编写冗余的错误检测代码[^1]。 ```javascript function stepOne() { return new Promise((resolve, reject) => { setTimeout(() => resolve("Step One"), 1000); }); } function stepTwo(input) { return new Promise((resolve, reject) => { if (input === "Step One") { resolve("Step Two"); } else { reject(new Error("Invalid input from Step One")); } }); } stepOne() .then(stepTwo) .then(result => console.log(result)) // 如果一切正常,输出 Step Two .catch(error => console.error(`Chain interrupted due to: ${error.message}`)); // 捕获来自 stepTwo 的错误 ``` 此示例展示了如何利用 `.catch` 终止一条 Promise 上的错误传播路径[^2]。 --- #### ### 4. 多次使用 `.catch` 尽管一般情况下只需要一个 `.catch` 即可覆盖整条 Promise 中的潜在问题,但在某些特殊场景下也可能连续多次调用 `.catch`。需要注意的是,只有当前 `.catch` 自身产生的新错误才会传递给下一个 `.catch`。 ```javascript new Promise((resolve, reject) => { resolve(true); }) .then(value => { if (!value) { throw new Error("Condition failed!"); } undefinedVariable + 5; // 制造运行时错误 }) .catch(err => { console.error("First catch:", err.message); nonExistentFunction(); // 再次制造新的错误 }) .catch(err => { console.error("Second catch:", err.message); // 此处捕获前一 catch 中的新错误 }); ``` 上述代码片段表明了不同层次间 `.catch` 的工作原理[^3]。 --- #### ### 5. 结合 `.finally` 使用 无论 Promise 是否成功还是失败,`.finally` 都会被执行,适合用来清理资源或者记录日志等无关业务成败的操作[^5]。 ```javascript fetch('https://jsonplaceholder.typicode.com/posts/1') .then(response => response.json()) .then(postData => console.log(postData.title)) .catch(error => console.error(`Failed fetching post title: ${error.message}`)) .finally(() => console.log("Fetching operation concluded.")); // 不论成功与否均显示结束提示 ``` 这段脚本体现了 `.finally` 在实际项目里的典型用途[^5]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值