目录
一、理解Promise
① 定义
1)抽象表达:
Promise是一门新的技术(ES6引入)
Promise是JS中进行异步编程的新解决方案(旧解决方案是单纯使用回调函数)
异步编程包括:
fs文件读取操作、 数据库操作、AJAX网络请求、定时器
2) 具体表达:
从语法上来说,Promise是一个构造函数(可以进行对象的实例化)
从功能上来说,promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
3)总结:
Promise是ES6引入的异步编程的处理方案,有三种状态:pending(进行中)、resolved(已完成)、rejected(已失败)。从语法上说,Promise是一个构造函数,可以实例化对象。封装异步操作,获取成功和失败的结果。
当Promise的状态由 pending 转变为 resolved 或者 reject 时,会执行相应的方法。
② 优点
支持链式调用,可以解决回调地狱的问题。
ES6中的 promise 的出现给我们很好的 解决了回调地狱的问题,在使用ES5的时候,在多层嵌套回调时,写完的代码层次过多,很难进行维护和二次开发以及不便于异常处理。
指定回调函数的方式更加灵活。
旧方案必须在启动异步任务前指定回调函数,而promise是在启动异步任务后,返回promise对象,给promise对象绑定回调函数(甚至可以在异步任务结束后指定多个回调函数) 。所以promise指定回调函数的方式更加灵活。
那我们可以把 promise 想象他是一种承诺,当它成功时执行一些代码,当它失败时执行一些代码。它更符合人类的行为思考习惯,而不在是晦涩难懂的冰冷语言。
③ 特点
只有异步操作的结果,可以决定当前是哪一种状态,任何其余操作都无法改变这个状态,也是“Promise”的名称的由来。同时,状态一旦改变,就无法再次改变状态。
从语法上说,Promise是一个对象,从他可以获取异步操作的消息。
④ 缺点
无法取消Promise,一旦新建他就会立即执行,无法中途取消。
其次,如果不设置回调函数,Promise内部跑出的错误无法反应到外部。当pending的时候,无法知道进展到了哪一步。
二、Promise 基本用法
ES6规定,Promise对象是一个构造函数,用来生成Promise实例。
下面代码创造了一个Promise实例。
const promise = new Promise(function(resolve, reject) {
if(success) {
resolve(value)
} else {
reject(error)
}
})
① resolve函数的作用
将Promise对象的状态从"未完成"变成"成功"。(即从pending变为resolved)。
将promise状态设置为成功,在异步操作成功的时候调用,并将异步操作结果作为参数传递出去。
② reject函数的作用
将Promise对象的状态从"未完成"变成"失败"(即从pending变为rejected)。
将promise状态设置为失败,在异步操作失败时调用,并将异步操作报出的错误作为参数传递出去。
③ then方法
promise实例生成后,可以用then方法分别指定 resolved 状态和 rejected 状态的回调函数。
promise.then(function(value) {
}, function(error) {
})
then方法可以接受两个回调函数作为参数
第一个回调函数:promise对象的状态变为resolved的时候调用;
第二个回调函数:promise对象的状态变为rejected时调用。
其中第二个函数是可选的,不一定需要提供。
这两个函数都接受Promise对象传出的值作为参数。
function timeout(ms) {
return new Promise((resolve, reject) => {
// setTimeout 传参
setTimeout(resolve, ms, 'done')
})
}
timeout(100).then((value) => {
// done
console.log(value)
})
上面代码中 timeout方法返回一个Promise实例,表示一段时间后才会发生的结果。过了指定的时间以后,Promise实例的状态变为 resolved,就会触发 then 方法绑定的回调函数。
let promise = new Promise(function(resolve, reject) {
console.log('Promise')
resolve()
})
promise.then(function() {
console.log('resolved')
})
console.log('Hi')
// Promise // Hi // resolved
上面代码中,Promise新建后立即执行,所以首先输出的是Promise,然后then方法指定回调函数,将在当前脚本所有同步任务执行完成后才会执行,所以resolved最后输出。
④ 一个异步加载图片的例子
function loadImageAsync(url) {
return new Promise(function(resolve, reject) {
const image = new Image()
image.onload = function() {
resolve(image)
}
image.onerror = function() {
reject(new Error('count not load...'))
}
image.src = url
})
}
上面代码中,使用 Promise 包装一个图片加载的异步操作,如果加载成功就调用resolve方法, 否则就调用rejected方法。
⑤ fs读取文件
旧方案:回调函数方式
promise:
三、Promise的其他常见方法
文章地址:Promise的其他方法_小草莓蹦蹦跳的博客-CSDN博客
① Promise.prototype.then()
② Promise.prototype.catch()
③ Promise.prototype.finally()
④ Promise.resolve()
⑤ Promise.reject()
⑥ Promise.all()
⑦ Promise.race()
四、promise的几个关键问题
① 改变promise状态的方法
1)resolve 函数
状态会从 pending 变为resolved
2)reject 函数
状态会从 pending 变为 rejected
3)抛出异常
状态会从 pending 变为 rejected
② 一个promise指定多个成功/失败回调函数,都会调用吗?
当promise改变为对应状态时,都会调用
③ 改变 promise 状态和 then 方法指定的回调函数谁先执行?
1)都有可能,正常情况下,是先指定回调再改变状态。但也可以先改变状态,再指定回调
以上这个代码是先执行回调,再改变状态
2)如何先改变再指定回调?
① 在执行器中直接调用 resolve()/reject()
② 延迟更长时间才调用 then()
3) 什么时候才能得到数据?
① 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据;
② 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据。
④ promise.then() 返回的新 promise 的结果状态由什么决定?
由then()指定的回调函数执行的结果决定
1) 如果抛出异常,新 promise 变成 rejected,reason为抛出的异常;
2) 如果返回的是非 promise 的任意值,新 promise 变为 resolved,value为返回的值;
3) 如果返回的是另一个新 promise,此 promise 的结果就会成为新 promise 的结果。
⑤ promise 如何串联多个操作任务?
1)promise 的 then() 返回一个新的 promise,可以看成 then() 的链式调用;
2)通过 then 的链式调用串联多个同步/异步任务;
⑥ promise异常穿透?
1)当使用 promise 的 then 链式调用,可以在最后指定失败的回调;
2)前面任何操作出了异常,都会传到最后失败的回调中处理;
⑦ 中断 promise 链?
当使用 promise 的 then 链式调用时,在中间中断,不再调用后面的回调函数。如何实现?
唯一办法:在回调函数中返回一个 pending 状态的 promise 对象
原理:promise.then() 返回的新 promise 的结果状态由then()指定的回调函数执行的结果决定。如果执行状态一直是pending,那么状态就不会发生改变,自然不会触发后面的 then 方法。