对promise 的理解

对于Promise的.then()方法,其实它接受两个参数。第一个参数是处理resolve状态(即成功状态)的回调函数,第二个参数是处理reject状态(即失败状态)的回调函数。也就是说,如果你提供了.then()的第二个参数,那么它将在Promise被rejected时执行。

然而,一般推荐使用.catch()处理Promise的错误状态,而非.then()的第二个参数。使用.catch()的好处是,它不仅可以捕捉到它之前链式调用中的所有错误,而且排查问题时也更为直观。

这里有一个例子可以帮助你理解:

let promise = new Promise(function(resolve, reject) {
  // 模拟一个错误
  reject("Error!");
});

promise
  .then(
    value => {
      // 成功的回调函数
      console.log("This won't run because the Promise is rejected.");
    }, 
    reason => {
      // 失败的回调函数
      console.log("Something went wrong: ", reason);
    }
  );

在这个例子中,我们创建了一个立即reject的Promise。.then()方法的第一个参数将不会被执行,因为Promise没有被resolve。第二个参数会被执行因为Promise被reject了,它将打印出"Something went wrong: Error!"。

需要注意的是,如果.then()中的第一个回调函数(即处理resolve状态的回调函数)在执行过程中出现错误,那么这个错误是无法被.then()中的第二个回调函数捕获的,但是可以被随后的.catch()捕获。

 

在您提供的代码中,您在每个.then()方法中添加了第二个参数——一个回调函数,该函数应该在Promise reject或抛出错误时执行。但是在这个例子中,makeAPromise()函数始终resolve而且没有抛出任何错误,所以这些第二个回调函数实际上永远不会被执行。

如果你想模拟一个错误,并看看这些回调函数如何工作,你可以修改makeAPromise()函数以使其有一定的概率reject。例如:

function makeAPromise(time){
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() < 0.5) {    // 50%的概率reject
        reject(`Error after ${time}`);
      } else {
        resolve(`Completed in ${time}`);
      }
    }, time);
  });
}

makeAPromise(1000)
  .then(
    value => {
      console.log(value); // 输出 "Completed in 1000"
      return makeAPromise(2000);
    },
    error => {
      console.log(error); // 输出例如 "Error after 1000"
    }
  )
  .then(
    value => {
      console.log(value); // 输出 "Completed in 2000"
      return makeAPromise(3000);
    },
    error => {
      console.log(error); // 输出例如 "Error after 2000"
    }
  )
  .then(
    value => {
      console.log(value); // 输出 "Completed in 3000"
    },
    error => {
      console.log(error); // 输出例如 "Error after 3000"
    }
  )
  .catch(error => {
    console.log("Caught by catch: ", error);
  });

注意,这些错误仍然不会被.catch()捕获,因为您在.then()中为每个Promise指定了错误处理回调。一旦一个步骤的错误被处理,后续步骤将再次回到fulfilled状态,所以catch()只会被触发如果你的.then()错误处理回调本身抛出错误。

所有这些都是为何一般推荐使用.catch()来处理错误的原因。通过.catch(),我们可以在Promises的链条中的任何一环中“捕获”到错误。由于catch()可以捕捉到前面步骤中的任何抛出的错误,它通常应该被放在链条的最末尾。

 

.then()的错误处理回调中,您可以返回另一个Promise,该语句与在解析回调中返回Promise的效果相同。如果此Promise解析,将进入下一次.then()的解析回调;如果此Promise被拒绝,则会触发链中下一步的错误处理。以下是如何在错误处理回调中引入新的Promise的示例:

function makeAPromise(time){
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() < 0.5) {    // 50%的概率reject
        reject(`Error after ${time}`);
      } else {
        resolve(`Completed in ${time}`);
      }
    }, time);
  });
}

makeAPromise(1000)
  .then(
    value => {
      console.log(value); // 如果成功,输出 "Completed in 1000"
      return makeAPromise(2000);  // 启动下一个Promise
    },
    error => {
      console.log(error); // 如果失败,输出例如 "Error after 1000"
      return makeAPromise(2000);  // 启动下一个Promise
    }
  )
  .then(
    value => {
      console.log(value); // 如果成功,输出 "Completed in 2000"
      return makeAPromise(3000);  // 启动下一个Promise
    },
    error => {
      console.log(error); // 如果失败,输出例如 "Error after 2000"
      return makeAPromise(3000);  // 启动下一个Promise
    }
  )
  .then(
    value => {
      console.log(value); // 如果成功,输出 "Completed in 3000"
    },
    error => {
      console.log(error); // 如果失败,输出例如 "Error after 3000"
    }
  )
  .catch(error => {
    console.log("Caught by catch: ", error); // 最终处理任何在链中未被处理的错误
  });

这个改编后的代码允许Promise链恢复正常,即使之前的步骤有被拒绝的Promise也能继续下去。这通常被用于你希望无论先前的步骤是否成功,都能执行后续步骤的情况。

 

如果在.then()的回调函数中返回了一个值(非Promise对象),那么下一个.then()接收的参数就是这个返回的值。

在你提供的代码中,你在第一个.then()函数的解析回调中返回了字符串 "123",那么该值就会被作为下一个.then()的解析回调的参数。如下例:

function makeAPromise(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`Completed in ${time}`);
    }, time);
  });
}

makeAPromise(1000) 
  .then(value => {
    console.log(value); // 输出 "Completed in 1000"
    return "123";  
  })
  .then(value => {
    console.log(value); // 输出 "123"
  });

在以上的代码中,"123" 被打印出来,因为它是在上一个.then()中返回的字符串,而且它也是下一个.then()的解析回调所接收的参数。

posted @   踏浪小鲨鱼  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示