0

0

深入浅析Nodejs异步编程中的Promise

青灯夜游

青灯夜游

发布时间:2021-07-07 11:44:50

|

2175人浏览过

|

来源于掘金社区

转载

本篇文章带大家了解一下nodejs异步编程中的promise,介绍一下promise比callback优秀在哪里。

深入浅析Nodejs异步编程中的Promise

【推荐学习:《nodejs 教程》】

什么是 Promise

Promise 是一种异步编程的解决方案!

  • 当前事件循环得不到的结果,但未来的事件循环会给到你结果
  • 是一个状态机
    • pengding
    • resolved
    • reejectd

从代码看状态流转是怎样的

pending 到 resolve 的流转测试

(function () {
  const res = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, 500);
  });
  console.log("500ms", res);

  setTimeout(() => {
    console.log("800ms", res);
  }, 800);
})();

打印出如下内容

1.png

结果是符合我们的预期的

  • 我们无法立即获取promise的结果,此时promise处于pending状态
  • 必须等待一段时间过后才能获取promise的结果,此时promise处于fulfilled状态

pending 到 reject 的流转测试

(function () {
  const res = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error("error"));
    }, 500);
  });
  console.log("500ms", res);

  setTimeout(() => {
    console.log("800ms", res);
  }, 800);
})();

打印出如下内容

2.png

结果是符合我们的预期的

  • 我们无法立即获取promise的结果,此时promise处于pending状态
  • 必须等待一段时间过后才能获取promise的结果,此时promise处于reject状态
注意:如果当 pengding 状态进入到 reject 状态,这个错误又没有正确捕获的话,这个错误就会被抛到 JS 的全局

reslove 状态流转到 reject 状态测试

(function () {
  const res = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, 300);
    setTimeout(() => {
      reject(new Error("error"));
    }, 500);
  });
  console.log("500ms", res);

  setTimeout(() => {
    console.log("800ms", res);
  }, 800);
})();

打印出如下内容

3.png

可以发现!

在 300ms 的时候promise的状态已经切换到了resolve, 切换后永远也无法到达reject状态

  • pending 只能流转到 resolve 或者 reject;
  • resolvereject 不能互相流转;

使用 then,catch 捕获 promise 的结果

(function () {
  const res = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(3);
    }, 300);
  })
    .then((result) => {
      console.log("result", result);
    })
    .catch((error) => {
      console.log("error", error);
    });

  console.log("300ms", res);

  setTimeout(() => {
    console.log("800ms", res);
  }, 800);
})();

打印出如下内容

4.png

可以发现

美图AI开放平台
美图AI开放平台

美图推出的AI人脸图像处理平台

下载
  • thenpromise 的状态流转到 reslove 状态可以拿到的结果
(function () {
  const res = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error("error-3"));
    }, 300);
  })
    .then((result) => {
      console.log("result", result);
    })
    .catch((error) => {
      console.log("error", error);
    });

  console.log("300ms", res);

  setTimeout(() => {
    console.log("800ms", res);
  }, 800);
})();

打印出如下内容

5.png

可以发现

catchpromise 的状态流转到 reject 状态可以拿到的结果, 并且之前全局的 JS 错误已经可以被 catch 捕获到了

.then .catch 总结

  • resolved 状态的 Promise 会回调后面的第一个 .then
  • rejected 状态的 Promise 会回调后面的第一个 .catch
  • 任何一个 rejected 状态切后面没有 .catch 的 Promise 会造成 Js 环境的全局错误

Promise 相比 callback 优秀的地方

解决异步流程控制问题-回调地狱

我们继续之前面试的例子

使用 Promise 改造 之前的 interview 函数

function interview() {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      if (Math.random() > 0.4) {
        // resolve, reject 只能接受一个参数
        resolve("success");
      } else {
        reject(new Error("fail"));
      }
    }, 1000);
  });
}

(function () {
  const res = interview();
  res
    .then((result) => {
      console.log("面试成功!我笑了");
    })
    .catch((error) => {
      console.log("面试失败!我哭了");
    });
})();

.then 中抛出错误的情况测试

function interview() {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      if (Math.random() > 0.4) {
        // resolve, reject 只能接受一个参数
        resolve("success");
      } else {
        reject(new Error("fail"));
      }
    }, 500);
  });
}

(function () {
  const promsie1 = interview();

  const promsie2 = promsie1.then((result) => {
    throw new Error("面试成功!我笑了,但是我拒绝了");
  });

  setTimeout(() => {
    console.log("promsie1", promsie1);
    console.log("promsie2", promsie2);
  }, 800);
})();

6.png

以上代码可以看出 ,**.then返回一个全新的 Promise, 此 Promise 的结果状态是由 .then 的回调函数的结果来决定的

  • 如果回调函数最终是throw, 则进入 rejected
  • 如果回调函数最终是return,则进入 resolved

.catch 中正常值的情况测试

function interview() {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      if (Math.random() > 0) {
        // resolve, reject 只能接受一个参数
        resolve("success");
      } else {
        reject(new Error("fail"));
      }
    }, 500);
  });
}

(function () {
  const promsie1 = interview();

  const promsie2 = promsie1.catch((result) => {
    return "虽然面试失败,但我还是笑了";
  });

  setTimeout(() => {
    console.log("promsie1", promsie1);
    console.log("promsie2", promsie2);
  }, 800);
})();

7.png

.catch 返回一个全新的 Promise, 此 Promise 的结果状态是由 .catch 的回调函数的结果来决定的

  • 如果回调函数最终是throw, 则进入 rejected
  • 如果回调函数最终是return,则进入 resolved

.catch,.then 里面再返回 Promise

function interview() {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      if (Math.random() > 0.4) {
        // resolve, reject 只能接受一个参数
        resolve("success");
      } else {
        reject(new Error("fail"));
      }
    }, 500);
  });
}

(function () {
  const promsie1 = interview();

  const promsie2 = promsie1
    .then((result) => {
      return new Promise(function (resolve, reject) {
        setTimeout(() => {
          resolve("面试成功!,给我400ms 总结一下");
        }, 400);
      });
    })
    .catch((result) => {
      return new Promise(function (resolve, reject) {
        setTimeout(() => {
          resolve("面试失败,给我400ms 总结一下");
        }, 400);
      });
    });

  setTimeout(() => {
    console.log("800ms promsie1", promsie1);
    console.log("800ms promsie2", promsie2);
  }, 800);

  setTimeout(() => {
    console.log("1000ms promsie1", promsie1);
    console.log("1000ms promsie2", promsie2);
  }, 1000);
})();

8.png

如果在 .catch,.then 中 返回 Promise, 则会等待此 Promise 的执行结果

如果回调函数最终 return 了 Promise,该 promise 和回调函数的 return 的 Promsie 状态保持一致, 这就表示了可以 在 Promise 的链式调用里面串行的执行多个异步任务!

Promise 实现多轮面试-串行

// round 面试第几轮
function interview(round) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      if (Math.random() > 0.4) {
        // resolve, reject 只能接受一个参数
        resolve("success");
      } else {
        const error = new Error("fail");
        reject({ round, error });
      }
    }, 500);
  });
}

(function () {
  interview(1)
    .then(() => {
      return interview(2);
    })
    .then(() => {
      return interview(3);
    })
    .then(() => {
      console.log("每轮面试都成功!我开心的笑了");
    })
    .catch((err) => {
      console.log(`第${err.round}轮面试失败了`);
    });
})();

Promise 的 .then .catch 把回调地狱变成了一段线性的代码!

Promise 实现多加公司面试-并行

// round 面试第几轮
function interview(name) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      if (Math.random() > 0.4) {
        // resolve, reject 只能接受一个参数
        resolve("success");
      } else {
        const error = new Error("fail");
        reject({ name, error });
      }
    }, 500);
  });
}

(function () {
  Promise.all([interview("tenxun"), interview("ali"), interview("baidu")])
    .then(() => {
      console.log("每家公司都面试成功了");
    })
    .catch((err) => {
      console.log(`面试${err.name}失败了`);
    });
})();

更多编程相关知识,请访问:编程视频!!

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

510

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

244

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

278

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5293

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

478

2023.09.01

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

Js中concat和push的区别
Js中concat和push的区别

Js中concat和push的区别:1、concat用于将两个或多个数组合并成一个新数组,并返回这个新数组,而push用于向数组的末尾添加一个或多个元素,并返回修改后的数组的新长度;2、concat不会修改原始数组,是创建新的数组,而push会修改原数组,将新元素添加到原数组的末尾等等。本专题为大家提供concat和push相关的文章、下载、课程内容,供大家免费下载体验。

218

2023.09.14

js截取字符串的方法介绍
js截取字符串的方法介绍

JavaScript字符串截取方法,包括substring、slice、substr、charAt和split方法。这些方法可以根据具体需求,灵活地截取字符串的不同部分。在实际开发中,根据具体情况选择合适的方法进行字符串截取,能够提高代码的效率和可读性 。

218

2023.09.21

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

9

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
快速入门Node.JS全套完整版
快速入门Node.JS全套完整版

共83课时 | 8.3万人学习

nodejs开发基础教程
nodejs开发基础教程

共15课时 | 4.5万人学习

JavaScript设计模式视频教程
JavaScript设计模式视频教程

共28课时 | 5.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号