promise

参考 Promises/A+, 实现一个Promise

定义状态

1
2
3
4
// define three states
const PENDING = 0
const RESOLVED = 1
const REJECTED = 2

version#0 (resolve/reject时变更状态)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyPromise {
constructor(executor) {
const resolve = () => {
this.state = RESOLVED
}
const reject = () => {
this.state = REJECTED
}

this.state = PENDING
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
}

version#1(Promise.resolve, Promise.reject实现)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyPromise {
constructor(executor) {
const getCallback = state => value => {
this.value = value;
this.state = state;
};
const resolve = getCallback(RESOLVED);
const reject = getCallback(REJECTED);
this.state = PENDING
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
static resolve(value) {
return new MyPromise((resolve) => resolve(value))
}

static reject(value) {
return new MyPromise((_, reject) => reject(value))
}
}

version#2 (实现 then 方法)

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
class MyPromise {
constructor(executor) {
const members = {
[RESOLVED]: {
state: RESOLVED,
then: onResolved => MyPromise.resolve(onResolved(this.value))
},
[REJECTED]: {
state: REJECTED,
then: () => this
},
[PENDING]: {
state: PENDING
},
}
const changeState = (state) => Object.assign(this, members[state])
const getCallback = state => value => {
this.value = value;
changeState(state);
};
const resolve = getCallback(RESOLVED);
const reject = getCallback(REJECTED);
changeState(PENDING)
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
...
}

version#3 (实现try捕获错误)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyPromise {
constructor(executor) {
const tryCall = cb => MyPromise.try(() => cb(this.value));
const members = {
[RESOLVED]: {
...
then: tryCall
},
...
}
...
}
...
static try(cb) {
return new MyPromise(resolve => resolve(cb()));
}
}

version#4 (实现 catch 方法, 翻转then)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyPromise {
constructor(executor) {
const tryCall = cb => MyPromise.try(() => cb(this.value));
const members = {
[RESOLVED]: {
state: RESOLVED,
then: tryCall
catch: () => this
},
[REJECTED]: {
state: REJECTED,
then: () => this
catch: tryCall
},
...
}
...
}
...
static try(cb) {
return new MyPromise(resolve => resolve(cb()));
}
}

version#5 (忽略连续调用 resolve 和 reject)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MyPromise {
constructor(executor) {
...
const apply = (value, state) => {
// 忽略连续调用 resolve 和 reject
if (this.state === PENDING) {
this.value = value;
changeState(state);
}
}
const getCallback = (state) => (value) => {
if (value instanceof MyPromise && state === RESOLVED) {
value.then((value) => apply(value, RESOLVED))
value.catch((value) => apply(value, REJECTED))
} else {
apply(value, state)
}
}
...
}
...
}

version#6 (返回 Promise)

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
class MyPromise {
constructor(executor) {
...
const laterCalls = []
const callLater = (getMember) => {
return (callback) => {
return new MyPromise((resolve) => {
laterCalls.push(() => resolve(getMember()(callback)))
})
}
}
const members = {
...
[PENDING]: {
state: PENDING,
then: callLater(() => this.then),
catch: callLater(() => this.catch),
}
}
...
const apply = (value, state) => {
if (this.state === PENDING) {
...
for (const laterCall of laterCalls) {
laterCall()
}
}
}
...
}
...
}

version#7

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
const PENDING = 0
const RESOLVED = 1
const REJECTED = 2
class MyPromise {
constructor(executor) {
const tryCall = cb => MyPromise.try(() => cb(this.value));
const laterCalls = []
const callLater = (getMember) => {
return (callback) => {
return new MyPromise((resolve) => {
laterCalls.push(() => resolve(getMember()(callback)))
})
}
}
const members = {
[RESOLVED]: {
state: RESOLVED,
then: tryCall,
catch: () => this,
},
[REJECTED]: {
state: REJECTED,
then: () => this,
catch: tryCall,
},
[PENDING]: {
state: PENDING,
then: callLater(() => this.then),
catch: callLater(() => this.catch),
},
}
const changeState = (state) => Object.assign(this, members[state])
const apply = (value, state) => {
if (this.state === PENDING) {
this.value = value
changeState(state)
for (const laterCall of laterCalls) {
laterCall()
}
}
}

const getCallback = (state) => (value) => {
if (value instanceof MyPromise && state === RESOLVED) {
value.then((value) => apply(value, RESOLVED))
value.catch((value) => apply(value, REJECTED))
} else {
apply(value, state)
}
}

const resolve = getCallback(RESOLVED)
const reject = getCallback(REJECTED)
changeState(PENDING)
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}

static resolve(value) {
return new MyPromise((resolve) => resolve(value))
}

static reject(value) {
return new MyPromise((_, reject) => reject(value))
}

static try(callback) {
return new MyPromise((resolve) => resolve(callback()))
}
}

增强 MyPromise , 添加一些方法 MyPromise.all, MyPromise.race



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
class MyPromise {
constructor(executor) {

}
...
static isMyPromise(arg) {
if (typeof arg === 'object' || typeof arg === 'function') {
if (typeof arg.then === 'function') {
return true
}
}
return false
}

// https://tc39.es/ecma262/#sec-promise.all
static all(promises) {
const promisesArray = Array.prototype.slice.call(promises)
const len = promisesArray.length
const results = []
let resultsConut = 0
return new MyPromise((resolve, reject) => {
const res = (val, i) => {
if (MyPromise.isMyPromise(val)) {
val
.then(v => {
res(v, i)
})
.catch(reject)
} else {
results[i] = val
resultsConut++
}
if (resultsConut === len) {
resolve(results)
}
}
promisesArray.forEach(res)
})
}
// https://tc39.es/ecma262/#sec-promise.race
static race(promises) {
const promisesArray = Array.prototype.slice.call(promises)
if (!promisesArray.length) {
// If the iterable argument is empty or if none of the promises in iterable ever settle
// then the pending promise returned by this method will never be settled.
return new MyPromise(() => {})
}
return new MyPromise((resolve, reject) => {
const res = (val) => {
if (MyPromise.isMyPromise(val)) {
val
.then(v => {
res(v)
})
.catch(reject)
} else {
resolve(val)
}
}
promisesArray.forEach(res)
})
}
}


参考
promisejs/Implementing
Promises/A+
Implementing JavaScript Promise in 70 lines of code!