专注于打造一个Promise轮子!

Promise A+

Promise A+ 规则,以下对其作了一些翻译

术语

  • “promise” 是一个带有then方法的对象或函数,且其行为服从定义
  • “thenable” 是一个带有then方法的对象或函数
  • “value” 是js中任意类型的值(包括undefined, thenable, promise等)
  • “exception” 是用throw抛出的异常
  • “reason” 是promise reject的原因

需求

Promise的状态

一个Promise具有三种状态:pending, fulfilled, rejected

  • 当pending时,可以转换到fulfilled或rejected状态
  • 当fulfilled时,不能转换到其他状态,且value必须被赋值,且值不可变(===判断)
  • 当rejected时,不能转换到其他状态,且reason必须被赋值,且值不可变(===判断)

then方法

一个Promise必须包含then方法来获取当前或者将来可能得到的value或reason

一个Promise的then方法可以接受两个参数:

1
primise.then(onFulfilled, onRejected)

  • onFulfilled,onRejected都是可选的,当他们不是函数时忽略之。
  • onFulfilled必须在promise的状态转变为fulfilled时才能调用,且入参为promise的value,有可能会被多次调用,调用的结果要一致。
  • onRejected必须在promise的状态转变为rejected时才能调用,且入参为promise的reason,有可能会被多次调用,调用的结果要一致。
  • onFulfilled,onRejected不能运行在仅存在平台上下文的环境中(这里的意思是,必须异步执行,在then执行之后的事件循环中,在新的上下文环境中)
  • onFulfilled,onRejected必须是函数
  • 一个promise对象的then可能被多次调用,如果promise对象的状态是fulfilled的,所有的onfulfilled回调都必须和原先的调用顺序一样调用,如果状态是rejected,所有的onRejected回调都必须和原先的调用顺序一样的调用。
  • then方法必须返回一个promise

    1
    promise2 = primise1.then(onFulfilled, onRejected)

    如果onFulfilled,onRejected返回的是一个值x,使用Promise Resolution Procedure解析
    如果onFulfilled,onRejected抛出了一个异常e,promise2必须在reject方法中捕获到e
    如果onFulfilled不是一个方法,而promise1的状态变为fulfilled了,则promise2的状态和value要和promise1的一致
    如果onRejected不是一个方法,而promise1的状态变为rejected了,则promise2的状态和reason要和promise1的一致

Promise Resolution Procedure

Promise Resolution Procedure:这是一个抽象的方法,入参为promise和一个value,就像这样[[Resolve]](promise, x)。

如果x是一个thenable的对象或方法,则尝试将其转化为promise对象,如果不是thenable的对象,则使用x作为promise的fulfilled状态的值。
[[Resolve]](promise, x):

  1. 如果x和promise指向同一个对象,则用TypeError作为reason拒绝promise
  2. 如果x是个Promise则采用其状态来执行:
    如果x的状态是pending,promise必须保持pending直到x的状态改变
    如果x的状态是fulfilled,promise使用x的value并将状态设置为fulfilled
    如果x的状态是rejected,promise使用x的reason并将状态设置为rejected
  3. 另外,如果x是个对象或函数
    如果x具有then方法,只用x作为this来调用这个then方法,then方法的入参为两个:resolvePromise,rejectPromise
    • 如果resolvePromise被调用,且传参为y,则使用[[Resolve]](promise, y)
    • 如果rejectPromise被调用,且reason为r,则使用r来拒绝promise
    • 如果resolvePromise,rejectPromise都被调用,或者调用了多个方法,则只执行第一个调用的方法,其他忽略
    • 如果调用then产生了错误,若resolvePromise,rejectPromise已被调用则忽略,否则使用错误来拒绝promise
  4. 最后,如果x是个基本类型,promise使用x的value并将状态设置为fulfilled

最后如果调用形成了迭代调用,最好能够给出处理方案。

Promise 初实现

根据Promise最简单API,先糊了一个最简单的实现,仅实现一层then,catch,对then和catch返回的东西并不作处理,不过架子基本是这样没错啦,之后就是在这基础上来实现更多的API~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
var MyPromise = (function() {
// 三种状态
const STATE = {
PENDING: 0,
RESOLVED: 1,
REJECTED: 2,
}
function MyPromise(asyncFunc){
this.state = STATE.PENDING; // 初始化状态
this.queueStack = []; // 初始化调用栈
resolveAsyncFunc.call(this, asyncFunc);
}
MyPromise.prototype.then = function(doSomething){
if(this.state === STATE.PENDING){
this.queueStack.push({
resolve: doSomething
})
}
if(this.state === STATE.RESOLVED){
}
return this;
}
MyPromise.prototype.catch = function(doSomething){
if(this.state === STATE.PENDING){
this.queueStack.push({
reject: doSomething
})
}
return this;
}
function resolveAsyncFunc(asyncFunc){
try{
asyncFunc(doResolve.bind(this), doReject.bind(this));
}catch(e){
doReject(e);
}
}
function doResolve(data){
this.state = STATE.RESOLVED;
this.queueStack
.filter(item => (!!item.resolve))
.forEach((item) => {
item.resolve(data)
})
}
function doReject(err){
this.state = STATE.REJECTED;
this.queueStack
.filter(item => (!!item.reject))
.forEach((item) => {
item.reject(err)
})
}
return MyPromise;
})();
const test = new MyPromise((resolve, reject) => {
let p = 'no';
setTimeout(function(){
p = Math.random();
if(p < 0.5) {
resolve(p);
}else{
reject(p);
}
}, 500);
});
test.then((data) => {
console.log(`received ${data}`);
}).catch((err) => {
console.log(`error ${err}`);
})