promise是什么
以下来自百度
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
promise图解
promise有两大状态,未决状态和已决状态
- 未决状态:PENDING
- 已决状态:RESOLVED/REJECTED
promise中有两个方法可以将未决状态推向已决状态
- resolve:将状态从PENDING推向RESOLVED
- reject:将状态从PENDING推向REJECTED
promise还有两个列表用来存储成功后的回调函数与失败的回调函数
thenables/catchables
图解如下
手动封装MyPromise
既然明白了Promise的原理,那么promise内部就要有4个变量来存储相应的状态
在这里封装的MyPromise没有添加链式调用的功能,因为链式调用还没有搞懂。。。如果你明白链式调用的原理,请联系15011177648(微信同号)
- 当前状态
- 值(后续处理函数的参数)
- 成功状态回调列表
- 失败状态回调列表
class MyPromise {
// 接受一个函数
constructor(fun) {
// 定义后续处理参数
this.value = undefined;
// 定义promise状态,最初是未决
this.status = "PENDDING";
// 定义成功后续处理函数列表
this.thenableList = [];
// 定义失败后续处理函数列表
this.catchableList = [];
// 将状态推向成功的函数
let resolve = (value) => {
this.changeStatus('RESOLVED', value);
// 循环执行成功队列的函数
this.thenableList.forEach((item) => {
item(this.value)
})
}
// 将状态推向失败的函数
let reject = (value) => {
this.changeStatus('REJECTED', value);
// 循环执行失败队列的函数
this.catchableList.forEach((item) => {
item(this.value)
})
}
// 尝试执行传进来的函数
try {
fun(resolve, reject);
} catch (e) {
reject(e)
}
}
// 改变状态
changeStatus(newStatus, value) {
// 由于状态是不可逆的,所以先盘算是不是未决,不是直接返回
if (this.status != "PENDDING") return
this.status = newStatus;
this.value = value
}
// 后续处理
settleHandle(newStatus, able, list) {
// 判断参数是否为函数
if (typeof able != 'function') {
return
}
// 判断状态
if (this.status == newStatus) {
// 在Promise中,后续处理函数应该是放在事件微队列,但是jsAPI无法将事件放入微队列,这里使用setTimeout的宏队列代替
// 如果已经是已决了,直接执行
setTimeout(() => {
able(this.value)
}, 0)
} else {
// 不是已决的话就放进任务队列,等待状态改变
list.push(able);
}
}
// 添加成功处理函数
then(thenable, catchable) {
this.settleHandle('RESOLVED', thenable, this.thenableList);
// 由于成功处理函数可接受两个参数,所以这里也要调一下失败处理函数
this.catch(catchable)
}
// 添加失败处理函数
catch(catchable) {
this.settleHandle('REJECTED', catchable, this.catchableList)
}
}
私有化变量
在上面的promise中,完成了promise的基本功能,但是真正的Promise的某些变量,外接是访问不到的(除了then,catch,finally都访问不到),所以我们使用闭包加符号来私有化变量。
有关符号的使用,我会再写一篇博客来介绍
const MyPromise = (() => {
const PENDING = 'pending',
RESOLVED = 'resolved',
REJECTED = 'rejected',
promiseValue = Symbol('后续处理参数'),
promiseStatus = Symbol('当前状态'),
thenables = Symbol('成功后的调用函数列表'),
catchables = Symbol('成功后的调用函数列表'),
changeStatus = Symbol('改变状态'),
settleHandle = Symbol('后续处理');
return class MyPromise {
// 新状态, then的参数
[changeStatus](newStatus, result, queue) {
if (this[promiseStatus] !== PENDING) {
//状态无法变更
return;
}
this[promiseStatus] = newStatus;
this[promiseValue] = result;
queue.forEach(handle => {
handle(this[promiseValue])
});
}
constructor(executor) {
this[promiseValue] = undefined;
this[promiseStatus] = PENDING;
this[thenables] = [];
this[catchables] = [];
const resolve = (result) => {
this[changeStatus](RESOLVED, result, this[thenables]);
}
const reject = (err) => {
this[changeStatus](REJECTED, err, this[catchables]);
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
// 后续事件, 立即执行状态, 后续事件列表
[settleHandle](handle, status, queueList) {
if (typeof handle !== 'function') {
return
}
if (this[promiseStatus] == status) {
setTimeout(() => {
handle(this[promiseValue])
}, 0)
} else {
queueList.push(handle);
}
}
then(thenable, catchable) {
this[settleHandle](thenable, RESOLVED, this[thenables])
this.catch(catchable)
}
catch(catchable) {
this[settleHandle](catchable, REJECTED, this[catchables])
}
}
})()
Promise的静态方法
promise还有一些静态方法(这些静态方法怎么用就不做赘述了)
- all
- rece
- resolve
- reject
现在我们来实现一下这四个静态方法
const MyPromise = (() => {
const PENDING = 'pending',
RESOLVED = 'resolved',
REJECTED = 'rejected',
promiseValue = Symbol('后续处理参数'),
promiseStatus = Symbol('当前状态'),
thenables = Symbol('成功后的调用函数列表'),
catchables = Symbol('成功后的调用函数列表'),
changeStatus = Symbol('改变状态'),
settleHandle = Symbol('后续处理');
return class MyPromise {
// ...(略)
// 静态方法-resolve
static resolve(data) {
if (data instanceof MyPromise) {
return data
} else {
return MyPromise(resolve => {
resolve(data)
})
}
}
// 静态方法-reject
static reject(reason) {
return MyPromise((resolve, reject) => {
reject(reason)
})
}
// 静态方法-all
static all(ProList) {
return new MyPromise((resolve, reject) => {
// 给每个promise对象注册后续处理
// 成功就查看是否全部成功,全部成功让all的promise也成功
// 失败就直接失败
let result = ProList.map((p) => {
let obj = {
value: undefined,
isResolved: false
}
p.then((data) => {
obj.value = data;
obj.isResolved = true;
// then的后续处理函数是放在微队列,所以当后续处理函数执行时result已经有值了
let filterProList = result.filter((item) => !item.isResolved);
if (filterProList.length == 0) {
resolve(result.map(r => r.value))
}
}, (reason) => {
reject(reason)
})
return obj
})
})
}
// 静态方法-race
static race(ProList) {
// 给每个promise注册后续处理函数,变为已决就将rece的promise推向对应状态
return new MyPromise((resolve, reject) => {
ProList.forEach((p) => {
p.then(data => {
resolve(data)
},err => {
reject(err)
})
})
})
}
}
})()