1. Promise是什么
1.1 理解Promise
-
抽象表达:Promise是JS中进行异步编程的新的解决方案(旧方案是单纯使用回调函数)
----异步编程:①fs文件操作 ②数据库操作 ③Ajax ④定时器 -
具体表达:
①从语法上看:Promise是一个构造函数 (自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法)
②从功能上看:promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
1.2 Promise的含义
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
1.3 Promise的状态
(1)Promise对象代表一个异步操作,有三种状态:pending(进行中)、 resolved/fulfilled(已成功)、rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected
注意
- 对象的状态不受外界影响
- 只有这两种,且一个
promise
对象只能改变一次- 一旦状态改变,就不会再变,任何时候都可以得到这个结果
- 无论成功还是失败,都会有一个结果数据。成功的结果数据一般称为
value
,而失败的一般称为reason
。
1.4 Promise对象的值
实例对象promise的另一个值 PromiseResult
保存着对象 成功/失败 的值(value
/reason
)
resolve/reject可以修改值
1.5 Promise的基本流程
2. Promise的使用
2.1 Promise的基本使用
Promise是一个构造函数,我们可以用new关键字生成一个promise实例来使用
let promise = new Promise((resolve, reject) => {
//做一些异步操作
setTimeout(() => {
console.log('success')
resolve('promise is success')
}, 2000)
})
Promise构造函数接受一个函数作为参数,在这个函数内执行一些异步操作
这个函数拥有两个参数:resolve和reject,这两个都是函数,js引擎会帮你传入
在函数内部调用他们的时候分别代表对外声明异步操作已经成功(resolve)或失败(reject)
为什么会设计的这样复杂?
setTimeout(() => {
return 1
}, 2000)
这是一个简单的回调方式处理异步操作的结果,但是回调函数被外层的定时器包裹
我们没法简单的拿到回调函数的返回值,这也是回调函数最大的缺陷
所以promise通过resolve和reject方法,对外传递一个可以轻易访问到信息
如果我们需要拿到并处理promise内部resolve的信息,需要使用then方法:
let promise = new Promise((resolve, reject) => {
//做一些异步操作
setTimeout(() => {
console.log('success')
resolve('promise is success')
}, 2000)
})
promise.then(value =>{
console.log(value)
},reason=>{
console.log(reason)
})
// promise is success
promise实例上的then方法是promise里最常用的方法,它接受的第一个参数就是promise中resolve出来的值,第二个参数就是reject出来的值,从而我们可以在这个函数内部获取和使用这个值
另一个常用方法是catch,如果这个promise异步操作出了问题
我们会在函数内部调用reject方法传递出去错误信息,代表promise出错了
这时候应该使用catch方法来处理错误信息:
let promise = new Promise((resolve, reject) => {
//做一些异步操作
setTimeout(() => {
console.log('error')
reject('promise is error')
}, 2000)
})
promise.then(value => console.log(value))
// 报错 Uncaught (in promise) promise is success
promise.catch(reason => console.log(reason))
// 不报错 输出 promise is error
catch方法只是then的一个别名,不过为了代码清晰易读
我们最好都是用catch,而不是给then传入两个参数,即用then方法处理执行成功的promise,用catch方法处理出错的promise
2.2 为什么要使用Promise
1. 指定回调函数的方式更加灵活
以前:必须再启动异步任务前指定
// 1. 纯回调的形式
// 成功的回调函数
function successCallback(result) {
console.log("声音文件创建成功:" + result);
}
// 失败的回调函数
function failureCallback(error) {
console.log("声音文件创建失败:" + error);
}
// 必须先指定回调函数,再执行异步任务
createAudioFileAsync(audioSettings, successCallback, failureCallback) // 回调函数在执行异步任务(函数)前就要指定
promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
// 2. 使用Promise
const promise = createAudioFileAsync(audioSettings); // 执行2秒
setTimeout(() => {
promise.then(successCallback, failureCallback) // 也可以获取
}, 3000);
2.支持链式调用,可以解决回调地狱问题
什么是回调地狱?
回调函数嵌套调用,外部回调函数异步执行的结果是其内部嵌套的回调函数执行的条件
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result:' + finalResult)
}, failureCallback)
}, failureCallback)
}, failureCallback)
回调地狱的缺点?
- 不便于阅读
- 不便于异常处理
解决方案
-
promise 链式调用
使用promise的链式调用解决回调地狱
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {console.log('Got the final result:' + finalResult)})
.catch(failureCallback)
终极解决方案
- async/await
回调地狱的终极解决方案 async/await
async function request() {
try{
const result = await doSomething()
const newResult = await doSomethingElse(result)
const finalResult = await doThirdThing(newResult)
console.log('Got the final result:' + finalResult)
} catch (error) {
failureCallback(error)
}
}
2.3 Promise的相关API方法
1.Promise.resolve 方法:Promise.resolve(value)
value:将被 Promise 对象解析的参数,也可以是一个成功或失败的 Promise 对象
返回:返回一个带着给定值解析过的 Promise 对象,如果参数本身就是一个 Promise 对象,则直接返回这个 Promise 对象。
- 如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象
let p1 = Promise.resolve(521);
console.log(p1); // Promise {<fulfilled>: 521}
- 如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
// resolve('OK'); // 成功的Promise
reject('Error');
}));
console.log(p2);
p2.catch(reason => {
console.log(reason);
})
3.Promise.all 方法:Promise.all(iterable)
iterable:包含 n 个 promise 的可迭代对象,如 Array 或 String
说明:返回一个新的 promise,只有所有的 promise 都成功才成功,只要有一个失败了就直接失败
let p1 = new Promise((resolve, reject) => {
resolve('OK');
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');
const result = Promise.all([p1, p2, p3]);
console.log(result);
3.Promise.race方法:Promise.race(iterable)
iterable:包含 n 个 promise 的可迭代对象,如 Array 或 String
说明:返回一个新的 promise,第一个完成的 promise 的结果状态就是最终的结果状态 谁先完成就输出谁(不管是成功还是失败)
const pRace = Promise.race([p1, p2, p3])
// 谁先完成就输出谁(不管是成功还是失败)
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
pRace.then(
value => {
console.log('race onResolved()', value)
},
reason => {
console.log('race onRejected()', reason)
}
)
//race onResolved() 2