promise事件
首先我们要理解一个概念,在ES6中,Promise发生的整个事件过程
其次记住一个核心点(贯穿全文):promise 不是消除回调,而是让回调变的可以控制
ES6 中将某一可能发生异步操作的事情,分成两个阶段:未决和已决阶段:
比如:某个窗口中的一个点击监听事件,监听是否被点击。
1.未决阶段: 监听元素是否被点击
2.已决阶段: 此时按钮已经被点击
这个事件总是从 未决阶段 发展到 已决阶段 ps:这里把事件逐步推向已决阶段,无论这个事件推向的结果如何(成功返回到一个结果/或者是报错)这都是叫已经推向了已决
ES6 分为三种状态:pending(挂起)、resolved(已处理)、rejected(已拒绝)
pending:挂起(属于未决阶段)
resolved:已处理(已决阶段中的一种状态) ----> 一个正常的逻辑处理后结果。ps:如if和else处理的两个结果 都是属于正常的逻辑处理。不包括在判断中加入手动推向rejected的操作
rejected:已处理(已决阶段的另外一个种状态)----> 如ajax在请求数据时,网络状态不好获取到的404等,通常用于表示有一个错误
我们将 把事情变为resolved状态的过程叫做:resolve,推向该状态时,可能会传递一些数据
我们将 把事情变为rejected状态的过程叫做:reject,推向该状态时,同样可能会传递一些数据,通常为错误信息
始终记住,无论是阶段,还是状态,是不可逆的!
已决阶段的后续处理
当事件到达已决阶段后的后续处理,不同的已决状态,决定了不同的后续处理:
resolved状态:--------->后续处理表示为thenable
rejected状态:---------->后续处理表示为catchable
因为后续处理可能有多个,因此会形成作业队列,这些后续处理会按照顺序,当状态到达后依次执行
我们将整件事称之为Promise
Promise的基本使用
const pro = new Promise((resolve, reject)=>{
// 未决阶段的处理
// 通过调用resolve函数将Promise推向已决阶段的resolved状态
// 通过调用reject函数将Promise推向已决阶段的rejected状态
// resolve和reject均可以传递最多一个参数,表示推向状态的数据
})
pro.then(data=>{
//这是thenable函数,如果当前的Promise已经是resolved状态,该函数会立即执行
//如果当前是未决阶段,则会加入到作业队列,等待到达resolved状态后执行(promise串联)
//data为状态数据
}, err=>{
//这是catchable函数,如果当前的Promise已经是rejected状态,该函数会立即执行
//如果当前是未决阶段,则会加入到作业队列,等待到达rejected状态后执行(promise串联)
//err为状态数据
})
Promise的静态成员
resolve(数据):该方法返回一个 resolved 状态的 promise ,传递的数据作为状态数据
reject(数据):该方法返回一个 rejected 状态的 promise ,传递的数据作为状态数据
关于从未决推向已决的过程:
上栗子
const pro = new Promise((resolve,reject) =>{
resolve(1)
})
console.log(pro)
pro为已决状态
区分栗子二:
const pro = new Promise((resolve,reject) =>{
console.log(`未决阶段`)
setTimeout(() => {
resolve(1)
}, 2000);
})
const pro2 = pro.then(result =>{
console.log(result)
})
console.log(pro)
console.log(pro2)
pro 在执行时 setTimeout 会把 resolve 放入宏队列中,2秒以后执行 resolve(1) 放入微队列中,并将构造函数从未决推向已决过程,故一开始pro是 pending 状态 2秒后变为resolved 状态
pro2 因为未对它进行推向已决的过程 所以会输出pending状态,所以不要因为调用输出了结果就把pro2认为是已决状态
Promise的线程顺序:
首先要先知道promise是一个异步处理过程,放入的是微队列中。
js线程中执行顺序为:同步代码执行 ----> 微队列 -----> 宏队列
先上个栗子
const pro = new Promise((resolve,reject) =>{
console.log(`未决阶段`)
setTimeout(() => {
console.log(`2秒后我执行了`)
}, 2000);
resolve(1)
})
const pro2 = pro.then(result =>{
console.log(result)
})
console.log(pro2)
console.log(`同步代码执行完毕`)
按照执行的顺序 这里需要注意的是 resolve(1) 属于微队列中,在这个函数中无论怎么变换位置 输出的顺序都会在宏队列之前
Promise串联、API
首先什么是promise的串联?它能解决什么事?
当函数已经推向到已决状态时,当后续函数需要用到之前的promise处理结果时,就需要用到 promise 串联概念 :
其实promise串联 可以抽象理解为:顾客排队买肉夹馍,老板需要依照次序给排队的客户服务的一个过程
pormise 中在排队中的顾客(还未服务到的顾客) 就是挂起(pending状态)---->前面排队服务完成的顾客会从挂起(pending)改变已决状态(resolved/rejected)
经过前面的知识总结,从这里我们应该知道:promise 不是消除了回调,而是在推向已决的过程中,都具备一个返回值!
promise的实质依旧是回调,就是因为具备了这个 返回值,我们才让这个回调的返回值变的可以控制,这也是promise优点和特点
Promise的API:
- then:注册一个从 promise-----> resolved 状态的后续处理函数
- catch:注册一个从 promise-----> rejected 状态的后续处理函数
- finally:注册一个从未决到已决状态的后续处理函数 ps: 无参数的传递,只要promise 到达已决阶段时,都会执行该函数
注:一旦状态推向了已决阶段,无法再对状态做任何更改
API举个栗子:
const pro = new Promise((resolve, reject) => {
reject(1);
})
pro.finally(() => console.log("finally1")) // finally1
pro.finally(() => console.log("finally2")) // finally2
pro.then(resp => console.log("then1", resp * 1)); // 不执行
pro.then(resp => console.log("then2", resp * 2)); // 不执行
pro.catch(resp => console.log("catch1", resp * 1)); // catch1 1
pro.catch(resp => console.log("catch2", resp * 2)); // catch2 2
补充
在同一个函数中多次使用 resolve 或者 reject 时 :只会执行第一个语句
const pro = new Promise ((resolve,reject) =>{
resolve(1) // 只会执行该语句
resolve(2); // 失效
resolve(3); // 失效
})
pro.then(data => {
console.log(data)
})
pro.catch(err => {
console.log(err)
})
)
栗子二:
const pro = new Promise((resolve, reject) => {
throw new Error("abc"); // 只会执行该语句
resolve(1); //无效
reject(2); //无效
resolve(3); //无效
reject(4); //无效
})
pro.then(data => {
console.log(data)
})
pro.catch(err => {
console.log(err)
})
补充静态成员
iterable这里按照数组来理解
- all (iterable):使用all,该 promise 对象在iterable参数对象里所有的 promise 对象都成功(resolve)的时候才会触发成功,会返回一个新的promise 。一旦 promise 对象触发 reject 时,则立即触发该 promise 对象的失败。Promise.all 方法常被用于处理多个 promise 对象的状态集合。
function getRandom(min, max) { // 取最大值和最小值中的一个随机函数
return Math.floor(Math.random() * (max - min)) + min;
}
const proms = [];
for (let i = 0; i < 10; i++) {
proms.push(new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.5) {
console.log(i, "完成");
resolve(i);
} else {
console.log(i, "失败")
reject(i);
}
}, getRandom(1000, 5000));
}))
}
//等到所有的promise变成resolved状态后输出: 全部完成
const pro = Promise.all(proms)
pro.then(data =>{
console.log(`全部完成`,data)
})
pro.catch(err =>{
console.log(`有失败的`,err)
})
console.log(proms)
- race(iterable):只要第一个调用是 resolve/reject 时 后续全是成功/失败,并返回该promise对象