0%

Promise 对象

Promise 对象

概述

是异步编程的一种解决方案。

从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。

Promise 状态

状态的特点

Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。除了异步操作的结果,任何其他操作都无法改变这个状态。

Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const p1 = new Promise(function(resolve,reject){
resolve('success1');
resolve('success2');
});
const p2 = new Promise(function(resolve,reject){
resolve('success3');
reject('reject');
});
p1.then(function(value){
console.log(value); // success1
});
p2.then(function(value){
console.log(value); // success3
});
状态的缺点

无法取消 Promise ,一旦新建它就会立即执行,无法中途取消。

如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。

当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

then 方法

then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调,两个函数只会有一个被调用。

then 方法的特点

在 JavaScript 事件队列的当前运行完成之前,回调函数永远不会被调用。

1
2
3
4
5
6
7
8
9
10
11
const p = new Promise(function(resolve,reject){
resolve('success');
});

p.then(function(value){
console.log(value);
});

console.log('first');
// first
// success

通过 .then 形式添加的回调函数,不论什么时候,都会被调用。

通过多次调用 .then ,可以添加多个回调函数,它们会按照插入顺序并且独立运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const p = new Promise(function(resolve,reject){
resolve(1);
}).then(function(value){ // 第一个then // 1
console.log(value);
return value * 2;
}).then(function(value){ // 第二个then // 2
console.log(value);
}).then(function(value){ // 第三个then // undefined
console.log(value);
return Promise.resolve('resolve');
}).then(function(value){ // 第四个then // resolve
console.log(value);
return Promise.reject('reject');
}).then(function(value){ // 第五个then //reject:reject
console.log('resolve:' + value);
}, function(err) {
console.log('reject:' + err);
});

then 方法将返回一个 resolved 或 rejected 状态的 Promise 对象用于链式调用,且 Promise 对象的值就是这个返回值。

then 方法注意点

简便的 Promise 链式编程最好保持扁平化,不要嵌套 Promise。
注意总是返回或终止 Promise 链。

1
2
3
4
5
const p1 = new Promise(function(resolve,reject){
resolve(1);
}).then(function(result) {
p2(result).then(newResult => p3(newResult));
}).then(() => p4());

创建新 Promise 但忘记返回它时,对应链条被打破,导致 p4 会与 p2 和 p3 同时进行。
大多数浏览器中不能终止的 Promise 链里的 rejection,建议后面都跟上 .catch(error => console.log(error));

手写 Promise

Promise 的调用方式,new Promise(executor), executor 两个参数,resolve,reject。

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
82
83
84
class Promise {
constructor(executor) {
const resolve = () => {}
const reject = () => {}
executor(resolve, rejcet)
}
}
//Promise 内部有三个状态,pending、fulfilled、rejected,初始是 pending,调用 resolve 后变为 fulfilled,,调用 reject 后变为 rejected。fulfilled 时会调用 then 注册的成功的回调,rejected 时会调用 then 注册的失败的回调。

// Promise 内部状态
const STATUS = { PENDING: 'PENDING', FUFILLED: 'FUFILLED', REJECTED: 'REJECTED' }
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined; // 成过的值
this.reason = undefined; // 失败的值
this.onResolvedCallbacks = []; // 存放成功的回调的
this.onRejectedCallbacks = []; // 存放失败的回调的
const resolve = (val) => {
if (this.status == STATUS.PENDING) {
this.status = STATUS.FUFILLED;
this.value = val;
// 成功时调用成功队列里的回调
this.onResolvedCallbacks.forEach(fn=>fn());
}
}
const reject = (reason) => {
if (this.status == STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
// 失败时调用失败队列里的回调
this.onRejectedCallbacks.forEach(fn=>fn());
}
}
try {
executor(resolve, reject);
} catch (e) {
// 出错走失败逻辑
reject(e)
}
}
then(onFulfilled, onRejected) { // swtich 作用域
let promise2 = new Promise((resolve, reject) => {
if (this.status === STATUS.FUFILLED) {
// to....
try {
let x = onFulfilled(this.value);
resolve(x);
} catch (e) {
reject(e);
}
}
if (this.status === STATUS.REJECTED) {
try {
let x = onRejected(this.reason);
resolve(x);
} catch (e) {
reject(e);
}
}
if (this.status === STATUS.PENDING) {
this.onResolvedCallbacks.push(() => { // todo..
try {
let x = onFulfilled(this.value);
resolve(x);
} catch (e) {
reject(e);
}
})
this.onRejectedCallbacks.push(() => { // todo..
try {
let x = onRejected(this.reason);
resolve(x);
} catch (e) {
reject(e);
}

})
}
})

return promise2;
}
}
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// 规范版
const STATUS = { PENDING: 'PENDING', FUFILLED: 'FUFILLED', REJECTED: 'REJECTED' }

// 我们的promise 按照规范来写 就可以和别人的promise公用
function resolvePromise(x, promise2, resolve, reject) {
// 规范 2.3.1
if (promise2 == x) { // 防止自己等待自己完成
return reject(new TypeError('出错了'))
}
// 规范 2.3.3
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
// x可以是一个对象 或者是函数
let called;
try {
// 规范 2.3.3.1
let then = x.then;
if (typeof then == 'function') {
// 2.3.3.3
then.call(x, function(y) {
// 规范 2.3.3.3.3
if (called) return
called = true;
// 规范 2.3.3.3.1
resolvePromise(y, promise2, resolve, reject);
}, function(r) {
// 规范 2.3.3.3.3
if (called) return
called = true;
// 规范 2.3.3.3.2
reject(r);
})
} else {
resolve(x); // 此时x 就是一个普通对象
}
} catch (e) {
// 规范 2.3.3.3.4.1
if (called) return
called = true;
// 规范 2.3.3.3.4
reject(e); // 取then时抛出错误了
}
} else {
resolve(x); // x是一个原始数据类型 不能是promise
}
// 不是proimise 直接就调用resolve
}
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = []; // 存放成功的回调的
this.onRejectedCallbacks = []; // 存放失败的回调的
const resolve = (val) => {
if(val instanceof Promise){ // 是promise 就继续递归解析
return val.then(resolve,reject)
}

if (this.status == STATUS.PENDING) {
this.status = STATUS.FUFILLED;
this.value = val;
// 发布
this.onResolvedCallbacks.forEach(fn => fn());
}
}
const reject = (reason) => {
if (this.status == STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
// 腹部
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve, reject);
} catch (e) {
// 出错走失败逻辑
reject(e)
}
}
then(onFulfilled, onRejected) { // swtich 作用域
// 可选参数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function'? onRejected: err=> {throw err}
let promise2 = new Promise((resolve, reject) => {
if (this.status === STATUS.FUFILLED) {
// to....
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === STATUS.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === STATUS.PENDING) {
// 装饰模式 切片编程
this.onResolvedCallbacks.push(() => { // todo..
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
})
this.onRejectedCallbacks.push(() => { // todo..
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);

})
}
});
return promise2;
}
}
  • 本文作者: David Xue
  • 本文链接: https://xdw-h.github.io/6/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!