一、什么是Promise
所谓的Promise,就是一个对象,用来传递异步操作的消息。Promise对象代表一个异步操作,它有3种状态:pending(进行中)、Resolved(已完成,也称Fulfilled)和Rejected(已失败)。一旦状态变更了以后,就不能再更改状态了。
Promise是一个构造函数,用来生成Promise实例,构造函数内部的代码是立即执行的。
如下方代码所示:
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们也是函数,由JS引擎提供,不用自己部署。
(1) resolve函数:将Promise对象的状态从“pending(进行中)”变成“Resolved(已完成)”。在异步操作成功时调用resolve函数,并将异步操作的相关结果作为参数传递出去。比如上面代码resolve(value)中的value,就是传递出去的参数。
(2) reject函数:将Promise对象的状态从“pending(进行中)”变成“Rejected(已失败)”。在异步操作失败时调用reject函数,并将异步操作报出的错误(通常是Error对象的实例)作为参数传递出去。比如上面代码reject(error)中的error,就是传递出去的参数。
Promise实例生成之后,可以用then方法分别指定Resolved状态和Rejected状态的回调函数。then方法接受两个回调函数作为参数:第一个回调函数必选,在Promise对象的状态变Resolved时调用,第二个回调函数可选,在状态变为Rejected时调用。这两个回调函数都接受Promise对象传出的值作为参数(也即上面代码Promise对象返回的的value是then方法中第一个回调函数的实参,上面代码Promise对象返回的error是then方法中第二个回调函数的实参)。
二、用promise解决回调地狱问题
1、什么叫回调函数
被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数,称为回调函数。
(1)同步回调:回调函数立即执行。例如:
上述代码中的回调函数greeting是立即执行的。
(2)异步回调:须等某个异步操作完成后,才执行回调函数。例如:
上述代码中,回调函数需等ajax请求到数据后才执行。
回调函数会引起回调地狱(callback hell)问题,也叫“末日金字塔”。
2、什么叫回调地狱
回调的本质是将回调函数作为参数传递给另一个函数,当处理比较复杂的需求时,回调函数作为参数一层层嵌套,代码结构会非常庞大臃肿,代码维护难度极高,这就叫回调地狱。
例如:
3、Promise如何解决回调地狱问题
(1)Promise实现了链式调用,代码更优雅,可读性更高
promise的then方法有返回值,且返回值依然是一个promise对象,且是一个全新的 promise实例。这样,我们就可以在then方法返回的promise对象后面链式地继续then。后面的then里面回调函数的参数就是上一个then里面return的内容。因为return 的value值会被包装成Promise.reslove(value) 。
采用链式的then可以指定一组按照次序调用的回调函数。第一个then方法指定的回调函数有可能返回的还是一个Promise对象(即有异步操作),这时,第二个then方法指定的回调函数就会等待这个Promise对象状态发生变化,再被调用。如果变为Resolved,就调用resolve函数;如果状态变为Rejected,就调用reject函数。
例如在公司某个事务需老板审批通过后,经理才能审批,则代码可以这样模拟:
多个then链式地调用下去,解决了回调地狱的那种复杂的多层嵌套。
(2)错误处理要好得多,所有错误都由块末尾的一个.catch块处理,而不是在“金字塔”的每一层单独处理。
范例:见上图代码块末尾的catch处理
(3)Promise.all实现了多个异步任务并发运行并为其结果创建承诺的功能
Promise.all(iterable) 方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败的原因是第一个失败 promise 的结果。
注意:
- 在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组,它包含所有的传入迭代参数对象的值(也包括非 promise 值)。
- 如果参数中包含非 promise 值,这些值将被忽略,但仍然会被放在返回数组中(如果 promise 完成的话)。
例如:
只有p1、p2、p3都resolved才会执行最后的then方法。
文章参考:
1、《ES6标准入门》阮一峰
2、异步JavaScript简介 | MDN
developer.mozilla.org/zh-CN/docs/…
3、回调函数术语表 | MND