JS系列之 Promise

1. Promise是什么

还记得第一次听到 JS 里有个这个东西,本能的中式英语翻译了一下,许诺?
我好好的搬个代码,我许什么诺?花里胡哨的名字
现在回头看看,它状态不可更改的特性也蛮符合这个名字,难道... 莫非这就是程序员的浪漫!!
(狗头)(我不信,阿里 pX 什么事的,果然男人有钱会变坏。我不会,我缺的就是 money)


好了,说回正题,让我们相信爱情的美好,看看这个 Promise 到底是什么

Promise 是异步编程的一种解决方案,比传统的回调函数和事件相比更加的合理,强大

1.1 Promise产生的原因,解决的痛点

在实际项目中,如果遇到这样一个情况:
我们需要根据第一个网络请求的结果,再去执行第二个网络请求,拿着第二个请求的结果再去执行第三个请求...

不使用 Promise 的代码大概是下面这样子:

请求1 (function (请求结果1) {
  请求2 (function (请求结果2) {
    请求3 (function (请求结果3) {
       ...
    })
  })
})

这样看其实还好,没有很恐怖!
但是如果业务需求再复杂一些,这个请求就要一直叠加下去。
而且更糟糕的是,实际应用中,每一个请求都会对请求数据进行处理,这样代码就会变得十分难看臃肿,而且基本上这段代码无法复用。
这就是大名鼎鼎的 回调地狱


JS 实现异步是通过回调函数实现的。就是把任务的第二段单独写在一个函数里,等到第一段有了结果需要执行第二段时,直接调用这个回调函数。
Promise 就是为了解决 回调地狱 问题提出的,它不是新的语法功能,而是一种新的写法,允许将回调函数的嵌套改变成链式调用。

21世纪了,打代码一定要有所追求,一定要优雅。所以很多大佬就想办法解决这个问题,要用一个更加优雅的代码组织方式解决异步嵌套的问题。想到了类似下面这种同步的写法,于是 Promise 规范就诞生了。

let 请求结果1 = 请求1();
let 请求结果2 = 请求2(请求结果1);
let 请求结果3 = 请求3(请求结果2);
...
// 还可以复用某一个请求
let 请求结果4 = 请求3(请求结果1);
let 请求结果5 = 请求2(请求结果3);

当然 Promise 也有它的不足,Promise 最大的问题是会代码冗余,一大堆then,原来的语义不清晰,这个之后我们再说。

那下面我们来看看什么是 Promise 规范

1.2 Promise 规范

  • Promise 构造函数:
    Promise 对象是一个构造函数,用来生成 Promise 实例
// 创建一个 promise 实例
const promise = new Promise(resolve, reject) {
  // ... some code 
  if (/* 异步操作成功 */) {
    resolve(value)
  } else {
    reject(error)
  }
}

Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject. 它们又是两个函数

  • promise 常规写法:
new Promise (请求1)
  .then(请求2(请求结果1))
  .then(请求3(请求结果2))
  .then(请求4(请求结果3))
  .then(请求5(请求结果4))
  .catch(...// 处理异常)

比较一下这种写法和上面的回调式的写法。我们不难发现,Promise 的写法更为直观,并且能够在外层捕获异步函数的异常信息。

  • Promise 常用的方法有哪些?它们的作用是什么?
    类方法:
  1. Promise.resolve
    Promise 对象必须 reslove 一个值才可以被之后的 then 接收。而 then 中的函数要 return 一个结果或者一个新的 Promise 对象 ( then 本身就会返回一个新 promise,如果没有 return 数据,下一个 then 接收的值就是 undefined ),才可以让之后的 then 回调接收

let p = new Promise((reslove) => {
  reslove(2)
  // return 2 无法传递给下面的then
})
p.then(v => v).then(v => console.log(v)) // 2
  1. Promise.reject
  2. Promise.race

    多个 Promise 任务同时执行,返回最先执行结束的 Promise 任务的结果,不管这个 Promise 结果是成功还是失败

  3. Promise.all

    将多个 Promise 实例,包装成一个新的 Promise 实例. const p = Promise.all([p1, p2, p3]) 多个 Promise 任务同时执行。如果全部成功执行,则以数组的方式返回所有 Promise 任务的执行结果。 如果有一个 Promise 任务 rejected,则只返回 rejected 任务的结果。

这里就不一一展开每个类方法的具体使用方法了,这些可以看阮一峰大神的 ES6 学习。请点击这里

实例方法:

  1. Promise.prototype.then

    作用是为 Promise 实例添加状态改变时的回调函数。
    第一个参数是reslove状态的回调函数
    第二个参数(可选)是rejected状态的回调函数

then 方法返回的是一个新的 Promise 实例,因此可以采用链式写法

then 这两个参数的返回值可以是一下三种情况中的一种

  • return 一个同步的值,或者undefined(没有返回一个有效值时,默认返回 undefined);
    返回一个 resolved 状态的 Promise 对象,值为 同步的值undefined
  • return另一个 Promise,then方法将根据这个Promise的状态和值创建一个新的Promise对象返回
  • throw一个同步异常,then方法将返回一个rejected状态的Promise,值是该异常
.then(() => {
  ...
  return 2;
  return Promise.resolve(2); // 与上面一样
})
  1. Promise.prototype.catch

    .then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数

2. Promise 与事件循环 3. 升级之 async / await

假如有这么个需求:有三个独立的请求,请求成功后改变数据,我们需要再请求成功后拿到最新数据,然后再去执行另一个函数。

function 1 () { return ...new Promise }
function 2 () { return ...new Promise }
function 3 () { return ...new Promise }
funciton 4 () { ... // 在1,2,3之后处理 }

// 在此触发上述函数
async function click () {
  await 1();
  await 2();
  await 3();
  4()
}
4. 8题掌握 Promise 的特性

Click Here

5. Promise 的实现 6. 自测小集
  1. Promise 链式调用的执行顺序 我们通过一道妈妈做饭的题目来看 Promise 的链式调用 按照书写习惯,从上到下 log 妈妈做饭的过程
new Promise((resolve, reject) => {
  console.log('妈妈要做饭');
  resolve();
}).then(() => {
  console.log('买菜');

  new Promise((resolve, reject) => {
    console.log('去菜市场');
    resolve();
  }).then(() => {
    console.log('买食物');
  }).then(() => {
    console.log('回家');
  })
}).then(() => {
  console.log('做菜');
})

先思考下这题输出什么?
来,上菜!

妈妈要做饭
买菜
去菜市场
买食物
做菜
回家

what!!!难道妈妈不爱我了,在外面做了饭也不给我吃了是吗?
不可能呀!!!

原文链接:juejin.im

上一篇:不用找UI, CSS也能搞定图片效果
下一篇:我写了一个青铜版vue

相关推荐

  • 🙋Hanjst汉吉斯特改进+enSafeExpression安全表达式等

    Hanjst汉吉斯特模版语言及模版引擎,近期持续改进升级。 这次改进主要是增加了对安全输出表达式兼容,由于涉及到对软件开发过程中的效率和软件运行效率的平衡和取舍,所以多写了几句,以描述这个权衡利弊对...

    6 个月前
  • 🙋Hanjst汉吉斯特升级:+showImageAsync及性能改进等

    自2019年元旦🙋Hanjst汉吉斯特 模板语言及其编译引擎发布,已经过去一年多了。 这期间随着 🙋Hanjst汉吉斯特 的推广应用,我们也陆续发布了如下一些更新内容: 🛠️Hanjst/汉吉...

    7 个月前
  • 🙋Hanjst汉吉斯特优化+JsonDataFromScript等

    近日继续对 🙋Hanjst汉吉斯特优化改进。这次的改进思考是从服务器端返回的 HanjstJsonData的容器设计问题。目前的做法是服务器端的HanjstJsonData放入终端页面的一个Div元...

    5 个月前
  • 😉我用 Nuxt.js 仿了个掘金

    前言 首先肯定是要夸夸掘金啦,最开始从 CSDN 到 博客园 再到 掘金,个人感觉掘金的技术氛围非常的nice,真是个宝藏社区👏。技术文章大多以前端为主,对前端开发者非常友好,质量也是歪瑞古的。

    6 个月前
  • 😀一个原生js弹幕库,基于 CSS3 Animation

    BulletJs 😀一个原生js弹幕库,基于 CSS3 Animation 项目地址 演示图 2020-08-13更新 采用rollup打包并发布到npm,rollup打包教程...

    12 天前
  • 😀一个原生js弹幕库

    danmujs 😀一个原生js弹幕库,基于 CSS3 Animation 地址、核心代码 本项目基于 rc-bullets,项目约70%的代码基于rc-bullets,首先要感谢这个项目的作者...

    9 个月前
  • 🕵️‍♀️由原型到JS中的“模拟类”

    讲述了有关 JavaScript 中原型相关知识,又引出了 JavaScript 中的**“类“**究竟是什么?,以及一系列相关问题。 一、前置知识 1、JavaScript 的面向对象(OOP) ​...

    8 个月前
  • 🔥《吊打面试官》系列 Node.js 必知必会必问!

    前言 codeing 应当是一生的事业,而不仅仅是 30 岁的青春🍚 本文已收录 Github,欢迎 Star,一起接水💧 作为一个在互联网公司面一次拿一次 Offer 的面霸,打败了无...

    8 个月前
  • 🔥 Promise|async|Generator 实现&原理大解析 | 9k字

    笔者刚接触async/await时,就被其暂停执行的特性吸引了,心想在没有原生API支持的情况下,await居然能挂起当前方法,实现暂停执行,我感到十分好奇。好奇心驱使我一层一层剥开有关JS异步编程的...

    8 个月前
  • 📝记录:近期面试JS的提问

    1、求y和z的值是多少? var x = 1; var y = 0; function add(n){n=n+1;} y = add(x); console.log(y); 答案:为un...

    1 个月前

官方社区

扫码加入 JavaScript 社区