Promise

解决

1) 解决并发问题 (同步的多个异步方法的执行结果 promise.all)
2) 解决链式调用问题 (先获取name,再获取age,再获取…) 回调地狱 解决多个回调嵌套的问题(不是完全解决,.then.then也是回调)

分析

Promise 是一个类

1) 每次new一个 Promise 都需要传递一个执行器,执行器(executor)是立即执行的

1
2
3
4
5
6
new Promise( ()=>{
console.log("init");
})
console.log('1');
// 这里先执行的是 init 再执行 1
// 结果:init 1

2) 执行器函数中有2个参数 resolve、 reject。
3) 默认Primose有3个状态:pedding、fulfilled、rejected。 pedding => resolve 表示成功 pedding=> reject 表示拒绝。
4) 如果一旦成功不能再失败, 一旦失败不能成功了 只有当状态为pending的时候才能改变。
5) 每个Promise都有一个then方法。

手写一个Promise

首先建2个文件 1.promise.js(用于执行一系列操作) promise.js(用于放置手写的Promise)

基础封装

【1】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1.promise.js
let Promise= require('./promise'); // 这里引入的是自己手写的Promise
let p = new Promise((resolve, reject) => {
resolve("我有钱");
//reject("我有钱");
//throw new Error("失败");
})
p.then(data=>{
console.log("成功的回调:", data);
},err=>{
console.log("失败的回调:", err);
})
// 执行结果:line4 成功的回调:我有钱
// 执行结果:line5 失败的回调:我有钱
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
// promise.js

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class Promise{
//1) 每次new一个 Promise 都需要传递一个执行器,执行器(executor)是立即执行的
constructor(executor){
// 不能用let 要如下 放在实例中 为了能在1.promise.js line4-5调用的时候把对应的成功的值和失败的值在line9、line11同样能拿到
// let value;
// let reason;
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
let resolve = (value) => {
this.value = value;
this.status = FULFILLED;
}
let reject = (reason) => {
this.reason = reason;
this.status = REJECTED;
}
// 创建promise executor会立即执行
// 2) 执行器函数中有2个参数 resolve,reject
executor(resolve, reject); // 且可以知道这2个参数是两个函数所以let resolve reject
}
// 如1.promise.jsline8 每个实例上还有then方法
// then方法会判断当前的状态
then(onFulfilled, onRejected){
if(this.status === FULFILLED){
onFulfilled(this.value);
}
if(this.status === REJECTED){
onRejected(this.reason);
}
}
}
// 导出当前类 commonjs定义方式
module.exports = Promise;

【1】中,1.promise.js依次取消注释执行line4、5


【2】
当执行1.promise.js中line6时

1
throw new Error("失败");

需要做异常处理:

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
// promise.js
class Promise{
constructor(executor){
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
let resolve = (value) => {
this.value = value;
this.status = FULFILLED;
}
let reject = (reason) => {
this.reason = reason;
this.status = REJECTED;
}
try{ // 注意 同步操作是可以用try catch来捕获的
executor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onRejected){
if(this.status === FULFILLED){
onFulfilled(this.value);
}
if(this.status === REJECTED){
onRejected(this.reason);
}
}
}
module.exports = Promise;

这时候执行1.promise.jsline6 就能在line11捕获输出,执行结果: 失败的回调 Error: 失败


【3】
当同时打开1.promise.jsline4、6或line5、6时,执行结果都是 失败的回调 Error: 失败,这里不符合分析的第4点,
只有当状态为pending时才能改变状态

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
// promise.js
class Promise{
constructor(executor){
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
let resolve = (value) => {
if(this.status === PENDING){ // 4)如果一旦成功不能再失败,只有当状态为pending的时候才能改变
this.value = value;
this.status = FULFILLED;
}
}
let reject = (reason) => {
if(this.status === PENDING){ // 4)如果一旦失败不能再成功 只有当状态为pending的时候才能改变
this.reason = reason;
this.status = REJECTED;
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onRejected){
if(this.status === FULFILLED){
onFulfilled(this.value);
}
if(this.status === REJECTED){
onRejected(this.reason);
}
}
}
module.exports = Promise;

【4】
查看文档 https://promisesaplus.com/ promises/A+
2.2.6 then may be called multiple times on the same promise 相同的promise被多次调用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
32
33
34
// 1.promise.js
let Promise= require('./promise');
let p = new Promise((resolve, reject) => {
resolve("我有钱");
reject("我有钱");
//throw new Error("失败");
})
p.then(data=>{
console.log("成功的回调", data);
},err=>{
console.log("失败的回调", err);
})

p.then(data=>{
console.log("成功的回调", data);
},err=>{
console.log("失败的回调", err);
})
p.then(data=>{
console.log("成功的回调", data);
},err=>{
console.log("失败的回调", err);
})
p.then(data=>{
console.log("成功的回调", data);
},err=>{
console.log("失败的回调", err);
})
// 执行结果:
// 成功的回调 我有钱
// 成功的回调 我有钱
// 成功的回调 我有钱
// 成功的回调 我有钱
// 多个成功回调 用原生的Promise执行结果也一样 这里面p.then p是一样的

【5】
1.promise.js改成如下:

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
// 1.promise.js
let Promise= require('./promise');
let p = new Promise((resolve, reject) => {
// 这里执行的是异步操作时
setTimeout(() => {
resolve("我有钱");
}, 0);
})
p.then(data=>{
console.log("成功的回调", data);
},err=>{
console.log("失败的回调", err);
})

p.then(data=>{
console.log("成功的回调", data);
},err=>{
console.log("失败的回调", err);
})
p.then(data=>{
console.log("成功的回调", data);
},err=>{
console.log("失败的回调", err);
})
p.then(data=>{
console.log("成功的回调", data);
},err=>{
console.log("失败的回调", err);
})

自己写的和原生的结果不同,原生的会等到异步执行结束再执行then,而自己写的直接执行的then导致没有内容输出,
当前执行异步时状态是pending 而我们这里then函数中PENDING状态还未写,如下修改:

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
// promise.js
class Promise{
constructor(executor){
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
// 2个数组存储
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if(this.status === PENDING){
this.value = value;
this.status = FULFILLED;
// 发布
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if(this.status === PENDING){
this.reason = reason;
this.status = REJECTED;
// 发布
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onRejected){
if(this.status === FULFILLED){
onFulfilled(this.value);
}
if(this.status === REJECTED){
onRejected(this.reason);
}
if(this.status === PENDING){
//可以直接push 但如果有其他todo 所以用下面的方式
//this.onResolvedCallbacks.push(onFulfilled(this.value));
this.onResolvedCallbacks.push(()=>{ // 订阅的过程 存储
//todo
onFulfilled(this.value);
})
this.onRejectedCallbacks.push(()=>{ // 订阅的过程
//todo
onRejected(this.reason);
})

}
}
}
module.exports = Promise;
// 执行结果:
// 成功的回调 我有钱
// 成功的回调 我有钱
// 成功的回调 我有钱
// 成功的回调 我有钱

这就是典型的发布订阅 当1.promise.js line4-7执行状态为pending时,p.then()里面的方法先存起来,等到定时器里面resolve的时候依次执行。
概括 订阅:弄个数组 存起来 ; 发布:将存起来的数组里面的内容执行一遍。
所以现在相当于1.promise.jsline9-29在订阅 line6在发布
这就是同步的时候直接触发,异步的时候发布订阅


链式调用(应用)

现在的需求:读取name中的值 再读取age中的值, 以前的做法如下:

1
2
3
4
5
6
7
8
9
10
11
let fs = require('fs');
fs.readFile(__dirname + '/name.txt', 'utf8', (err, data)=>{
if(err){
console.log(err);
}
fs.readFile(__dirname + '/age.txt', 'utf8', (err, data)=>{
if(err){
console.log(err);
}
})
})

现在用promise做法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let fs = require('fs');
function readFile(...args){
return new Promise((resolve, reject) => {
fs.readFile(...args, (err, data)=>{
if(err) reject(err);
resolve(data);
})
})
}
readFile(__dirname + '/name.txt', 'utf8').then(data=>{
console.log(data);
},err=>{
console.log(err);
})

成功之后不通过回调,而是通过then
readFile(__dirname + ‘/name.txt’, ‘utf8’) 返回的是Promise实例,记住 能then的就是Promise实例
如果需要改造成Promise 就先将回调的方法 改成Promise
完整代码如下:
【1】then方法中返回: 1) 普通值

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
let fs = require('fs');
function readFile(...args){
return new Promise((resolve, reject) => {
fs.readFile(...args, (err, data)=>{
if(err) reject(err);
resolve(data);
})
})
}
// Promsie链式调用
// then方法中返回: 1) 普通值 指不是promise也不报错 如line14 它会把值传到then的外层如line18
readFile(__dirname + '/name.txt', 'utf8').then(data=>{
//console.log(data);
return false
},err=>{
console.log(err);
}).then(data=>{ // step: 1
console.log("successline18:", data);
//throw new Error('err'); //step: 2 + 3 // 想让下一个then走失败 需要 1)返回一个失败的promise 或者抛出一个异常
return new Promise((resolve, reject) => {
reject('err');
})
},err=>{
console.log('errline24:', err);
})
.then(data=>{ // step: 2
console.log("successline27:", data);
},err=>{
console.log('errline29:', err);
})
.then(data=>{ // step: 3
console.log("successline32:", data);
},err=>{
console.log('errline34:', err);
})

step1: line12 then里面返回的line14 它会把值传到then的外层到line18 可以看到打印结果: successline18: false
step2: 第一步走的成功 希望能走失败,现加入了line19 或line20-22 结果: line29
step3: 可以看到经历了第二步的失败 第三部从line29打印出来 失败也可以变成成功 结果:line32

1
2
3
4
5
6
7
8
9
10
// 打印结果:
successline18: false
errline29: err
successline32: undefined
// 如果line19执行,line20-22注释
// 打印结果
successline18: false
errline29: Error: err
at readFile.then.then.data (e:\.....js:20:11)
successline32: undefined

【2】then方法中返回: 2) 返回的是一个promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let fs = require('fs');
function readFile(...args){
return new Promise((resolve, reject) => {
fs.readFile(...args, (err, data)=>{
if(err) reject(err);
resolve(data);
})
})
}
readFile(__dirname + '/name.txt', 'utf8').then(data=>{
// 这里先调用name 成功之后 再调用age 如下
// 返回的是一个promise 则会执行 并根据状态 走外层then方法 line15
return readFile(__dirname + '/age.txt', 'utf8');
})
.then(data=>{
console.log(data);
},err=>{
console.log('err:', err);
})
// 执行结果: 18(age.txt里面的内容)

所以可以用这种方式来解决回调嵌套的问题 并且很容易捕获到错误
并且当line10读取报错(假设读取的是‘/name11.txt’),首先找then自身的错误处理,这里line14没有错误处理就找下一个line18去输出, 同样的line13读取报错(假设读取的是‘/age.txt123’)也可以在line18获取

1
2
3
4
5
6
7
8
9
10
11
12
13
// 如果这里line4-6添加了err
readFile(__dirname + '/name.txt11', 'utf8').then(data=>{
return readFile(__dirname + '/age.txt', 'utf8');
},err=>{
console.log(err);
})
.then(data=>{
console.log(data);
},err=>{
console.log('err:', err);
})
// line5输出报错信息
// line8 undefined

总结:
链式调用 如果返回一个普通值 会走下一个then的成功
抛出错误 走then失败的方法
如果是promise 就让promise执行 采用它的状态
是返回了一个新的promise 来实现链式调用


继续封装 链式调用

【6】
当一个promise的then方法中返回了一个普通值, 会将这个普通纸传到外层then的回调里 如下面的line6
这里p这个promise调用p.then之后返回的是一个新的promsie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1.promsie.js
const Promise = require('./promise');
let p = new Promise((resolve, reject) => {
resolve('hello')
})
p.then(data=>{
return data;
//throw new Error('err');
}).then(data=>{
console.log("成功:",data)
},err=>{
console.log('err:', err);
})
// 执行结果: 成功: hello
1
2
3
4
5
// 这里p这个promise调用p.then之后返回的是一个新的promsie
p.then(data=>{
return data;
//throw new Error('err');
})

所以这里面promise.js改为:

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
// promise.js
/**********************************这部分line35-41 只展示了成功的情况 后面会将3种状态都加进去*************/
class Promise{
constructor(executor){
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
// 2个数组存储
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if(this.status === PENDING){
this.value = value;
this.status = FULFILLED;
// 发布
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if(this.status === PENDING){
this.reason = reason;
this.status = REJECTED;
// 发布
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onRejected){
// then 方法调用后 会返回一个新的promise
let promise2 = new Promise((resolve, reject) => {
// 先以成功为例 1.promise.js line6-9 这个成功的方法里面 注释line8
// 首先拿到它的结果 line6 data
let x = onFulfilled(this.value); // 这里的this.value就是data
// line7 再将这个结果返回
resolve(x); // return data;
})
return promise2;
if(this.status === FULFILLED){
onFulfilled(this.value);
}
if(this.status === REJECTED){
onRejected(this.reason);
}
if(this.status === PENDING){
this.onResolvedCallbacks.push(()=>{
//todo
onFulfilled(this.value);
})
this.onRejectedCallbacks.push(()=>{
//todo
onRejected(this.reason);
})

}
}
}
module.exports = Promise;

现在将1.promise.js中line6注释,line7打开

promise.js代码中需要捕获错误,如下:

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
class Promise{
constructor(executor){
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
// 2个数组存储
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if(this.status === PENDING){
this.value = value;
this.status = FULFILLED;
// 发布
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if(this.status === PENDING){
this.reason = reason;
this.status = REJECTED;
// 发布
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onRejected){
let promise2 = new Promise((resolve, reject) => {
if(this.status === FULFILLED){
// 如果promise.js line8 抛出错误
try {
let x = onFulfilled(this.value); // 让then中的方法执行 拿到它的返回值
resolve(x);
} catch (error) {
reject(error)
}
}
if(this.status === REJECTED){
try {
let x = onRejected(this.reason);
reject(x);
} catch (error) {
reject(error)
}
}
if(this.status === PENDING){
this.onResolvedCallbacks.push(()=>{
//todo
try {
let x = onFulfilled(this.value);
resolve(x);
} catch (error) {
reject(error)
}
})
this.onRejectedCallbacks.push(()=>{
//todo
try {
let x = onRejected(this.reason);
reject(x);
} catch (error) {
reject(error)
}
})
}
})
return promise2;
}
}
module.exports = Promise;

【7】
当一个promise的then中返回一个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
// 1.promise.js
const Promise = require('./promise');
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hello');
});
})
p.then(data=>{
return new Promise( (resolve, reject) => {
setTimeout(() => {
resolve("word")
});
})
}).then(data=>{
console.log("成功:",data)
},err=>{
console.log('err:', err);
})
// 调用当前的promise.js
// 执行结果:
/*
成功: Promise {
value: undefined,
reason: undefined,
status: 'PENDING',
onResolvedCallbacks: [],
onRejectedCallbacks: [] }
*/

会把状态为PENDING状态的结果返回到line14的data

1
2
3
4
5
6
 new Promise( (resolve, reject) => {
setTimeout(() => {
resolve("word")
});
})
// 会直接把这个值传递给 data 也就是x 是个等待状态

我们希望的是能把返回值里面的promise执行完之后再传到then
所以现在需要判断x是否为promise
这里可以看 promises/A+ 里面2.2.7 resolvePromise , 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
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
// promise.js
const resolvePromise = (promise2, x, resolve, reject) => { // promise的处理函数
resolve(x);
// 处理x类型 来决定是调用resolve 还是reject
}
class Promise{
constructor(executor){
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
// 2个数组存储
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if(this.status === PENDING){
this.value = value;
this.status = FULFILLED;
// 发布
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if(this.status === PENDING){
this.reason = reason;
this.status = REJECTED;
// 发布
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onRejected){
let promise2 = new Promise((resolve, reject) => {
if(this.status === FULFILLED){
// 如promises/A+ 2.2.4,当前onFulfilled、onRejected不能在当前上下文中执行,为了确保promise2存在
setTimeout(()=>{// 当前line43拿到的是promsie2的值,在line37被定义的,直接在line44是拿不到的 所以这里加了一个定时器,让中间这段代码变成异步的,这样会等待line37new完Promise之后再拿到promise2
try {
let x = onFulfilled(this.value); // 问题:这里的x是promise 等待状态的值
//resolve(x);
resolvePromise(promise2, x, resolve, reject);
// 这里要拿x的值来判断promise2是成功还是失败,所以这里要把x、promsie2都传过去
} catch (error) {
reject(error)
}
})
}
if(this.status === REJECTED){
setTimeout( ()=>{
try {
let x = onRejected(this.reason);
//reject(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
if(this.status === PENDING){
this.onResolvedCallbacks.push(()=>{
//todo
setTimeout( ()=>{
try {
let x = onFulfilled(this.value);
//resolve(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
})
this.onRejectedCallbacks.push(()=>{
//todo
setTimeout( ()=>{
try {
let x = onRejected(this.reason);
//reject(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
})
}
})
return promise2;
}
}
module.exports = Promise;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const Promise  = require('./promise');
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hello');
});
})
let promise2 = p.then(data=>{ /*************************这里解析上面promise.js line43*/
return new Promise( (resolve, reject) => {
setTimeout(() => {
resolve("word")
});
})
})
promise2.then(data=>{ /*****************************这里解析上面promise.js line43*/
console.log("成功:",data)
},err=>{
console.log('err:', err);
})
// 这里的line8-12就是上面的x,x的值来决定promise2是成功还是失败,所以都要传过去,然后再让promise2走resolve还是reject

【8】
现在来处理resolvePromise函数

1
2
3
4
5
6
7
8
9
10
11
12
13
// 1.promise.js
const Promise = require('./promise');
let p = new Promise((resolve, reject) => {
resolve('hello');
})
let promise2 = p.then(data=>{
return promise2;
})
promise2.then(data=>{
console.log("成功:",data)
},err=>{
console.log('err:', err);
})
1
2
3
4
5
6
7
8
9
10
11
// promise.js
const resolvePromise = (promise2, x, resolve, reject) => { // promise的处理函数
//resolve(x)
// 处理x类型 来决定是调用resolve 还是reject
// 1.promise.js当我们处理的line5 then里面的promise有可能是原生的或者别人写的,所以必须要写的严谨 promises/A+ 2.3下面的内容可以看看 写的很详细
// 状况1: 2.3.1 If promise and x refer to the same object, reject promise with a TypeError as the reason. 这里的promise就是promise2 如 1.promise.js line5的then要等line6执行结束之后再执行下面的, let promise2,return promise2 意思是自己等自己 这样肯定是不行的
// 执行: ① 将1.promise.js line2注释 用原生的Promise 打印 err: TypeError: Chaining cycle detected for promise #<Promise> (死循环了) ② 现在用我们自己的Promsie,所以当前line8做了判断
if(promise2 === x){ //自己等待自己
return reject(new TypeError(`Chaining cycle detected for promise #<Promise>`));
}
}

【9】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/***************针对 promise.js line 12  2.3.3.2 取then的过程中抛出异常 */
// 1.promise.js
const Promise = require('./promise');
let obj = {};
Object.defineProperty(obj, "then", {
get(){
throw new Error("失败");
}
})
let p = new Promise((resolve, reject) => {
resolve('hello');
})
let promise2 = p.then(data=>{
return obj; // 这里会抛出异常
})
promise2.then(data=>{
console.log("成功:",data)
},err=>{
console.log('err:', err);
})
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
// promise.js
const resolvePromise = (promise2, x, resolve, reject) => {
// 处理x类型 来决定是调用resolve 还是reject
if(promise2 === x){ //自己等待自己
return reject(new TypeError(`Chaining cycle detected for promise #<Promise>`));
}
//
if( (typeof x === 'object' && x !== null) || (typeof x === 'function')){
// 这里可能是promise 判断是不是promise 有没有then方法 这里直接看 2.3.3 Otherwise, if x is an object or function (promise a+ 2.3.3下面的内容包括2.3.2的)
//let then = x.then; // 2.3.3.1 看看有没有then方法
// 2.3.3.2 取then的过程中抛出异常
try{
let then = x.then;
// 2.3.3.3 If then is a function, call it with x as this, first argument resolvePromise, and second argument resolvePromise, where
if(typeof then === 'function'){ // 这一步判断是否有then方法
// 我现在我们可以认为是promise了
//x.then(()=>{},()=>{});
then.call(x, y=>{ // 如果是promise 就采用promise的结果
resolve(y)
}, r=>{
reject(r);
})
// 当前 line17 和 line18-22功能上是一样的,为什么用下面的,因为有可能line17 x.then会报错,而line13这里let 的then已经做过判断了不会报错,所以then.call(x)这样写
}else{ // 2.3.3.4 If then is not a function, fulfill promise with x
resolve(x); // 常量直接抛出去 可在1.promise.js line14 用 return [1,2,3] 打印试试
}
}catch(e){
reject(e); // 取then抛出异常
}


}else{ // 2.3.4 If x is not an object or function, fulfill promise with x. (promise a+)
resolve(x); // 这里可以在 3.promise.js line 14 传个普通值测试
}
}

小结: 判断是否为promise

1
2
3
4
5
6
7
8
9
10
11
12
1if( (typeof x === 'object' && x !== null) || (typeof x === 'function'))
2let then = x.then; if(typeof then === 'function')
// 是否是对象、或者函数 并且有then方法


// 也可以
export function smellLikeAPromise(promise) {
if (promise instanceof Promise) {
return true;
}
return typeof promise === 'object' && promise.then === 'function' && promise.catch === 'function';
}

小知识点: then.call(x) 指 让then的this指向x 等价于 x.then


【10】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1.promise.js
const Promise = require('./promise');
let p = new Promise((resolve, reject) => {
resolve('hello');
})
let promise2 = p.then(data=>{
return new Promise( (resolve, reject) => {
setTimeout(()=>{
resolve(new Promise( (resolve, reject)=>{
setTimeout(() => {
resolve("hello")
});
}))
})
})
})
promise2.then(data=>{
console.log("成功:",data)
},err=>{
console.log('err:', err);
})

当如1.promise.js line 6-16之间嵌套了多个promise 我们希望的是能够执行到最里面的resolve或者reject结束之后再执行下一个then方法,即有可能上面resolvePromise函数里line18的y是个promise ,所以下面需要对y的类型做判断

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
// promise.js
const resolvePromise = (promise2, x, resolve, reject) => {
if(promise2 === x){ //自己等待自己
return reject(new TypeError(`Chaining cycle detected for promise #<Promise>`));
}
let called; // 默认没有调用成功和失败
if( (typeof x === 'object' && x !== null) || (typeof x === 'function')){
try{
let then = x.then
if(typeof then === 'function'){
then.call(x, y=>{
//resolve(y);
if(called) return;// 防止多次调用
called = true;
resolvePromise(promise2, y, resolve, reject); // 这里实现递归解析
}, r=>{
if(called) return;// 防止多次调用
called = true;
reject(r);
})
}else{
resolve(x);
}
}catch(e){
if(called) return;// 防止多次调用
called = true;
reject(e);
}
}else{
resolve(x);
}
}

参考promsies/A+ 2.3.3.3 If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
如果1.promise.js line7-15返回的是别人封装的Promise,假设它里面并没有做调取成功了之后不能再掉失败,调取了失败之后不能再调成功的判断,所以上面新增了一个 called 用来防止多次调用。


【11】
这里对应promises/A+ 2.2.1里面的几点

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
// 1.promise.js
const Promise = require('./promise');
/***********情况1********************************/
let p = new Promise((resolve, reject) => {
resolve('hello');
})
.then()
.then(data=>{
console.log("成功line9:",data)
},err=>{
console.log('errline11:', err);
})
// 调用原生Promise的结果: 成功line9: hello

/***********情况2*******************************/
let p = new Promise((resolve, reject) => {
reject('hello');
})
.then()
.then(data=>{
console.log("成功line21:",data)
},err=>{
console.log('errline23:', err);
})
// 调用原生Promise的结果: errline23: hello

/***********情况3********************************/
let p = new Promise((resolve, reject) => {
reject('hello');
})
.then(null, err=>{
//return err; // 如果这里这样写,下一个then会从成功传出来line36 打印结果:成功line36:hello
throw err; // 把错误抛出 这样 下一个then才会继续走error 打印结果: errline38: hello
})
.then(data=>{
console.log("成功line36:",data)
},err=>{
console.log('errline38:', err);
})

有一种穿透的感觉 这个then里没有写,就到下一个then,代码如下line34-35直接把值往下传

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
// promise.js
class Promise{
constructor(executor){
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
// 2个数组存储
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if(this.status === PENDING){
this.value = value;
this.status = FULFILLED;
// 发布
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if(this.status === PENDING){
this.reason = reason;
this.status = REJECTED;
// 发布
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);
}
}
then(onFulfilled, onRejected){
//可选参数 没传就给一个默认参数即可
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val=>val;
onRejected = typeof onRejected === 'function' ? onRejected : err=>{throw err};
let promise2 = new Promise((resolve, reject) => {
if(this.status === FULFILLED){
setTimeout(()=>{
try {
let x = onFulfilled(this.value);
//resolve(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
if(this.status === REJECTED){
setTimeout( ()=>{
try {
let x = onRejected(this.reason);
//reject(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
if(this.status === PENDING){
this.onResolvedCallbacks.push(()=>{
//todo
setTimeout( ()=>{
try {
let x = onFulfilled(this.value);
//resolve(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
})
this.onRejectedCallbacks.push(()=>{
//todo
setTimeout( ()=>{
try {
let x = onRejected(this.reason);
//reject(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
})
}
})
return promise2;
}
}

情况4:resolve里面返回了一个promise 可以分别用原生的和自己写的做对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1.promise.js
/***********情况4********************************/
const Promise = require('./promise');
let p = new Promise((resolve,reject) => {
resolve(new Promise( (resolve, reject) => {
setTimeout( ()=>{
resolve("hello");
},1000);
}))
}).then(data=>{
console.log(data);
},err=>{
console.log(err)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// promise.js
let resolve = (value) => {
// 这里的value 就是 1.promise.js line5 resolve里面返回的promise 所以这里也要对value的值做解析
if(value instanceof Promise){
// 如果一个promise resolve了一个新的promise 会等到这个内部的promise执行完成
return value.then(resolve, reject ); // 和resolvePromise的功能一样
}

if(this.status === PENDING){
this.value = value;
this.status = FULFILLED;
// 发布
this.onResolvedCallbacks.forEach(fn => fn());
}
}

情况5:
如下情况 catch line10-12 和 line13-15(这2种情况)可用原生方法试一下 效果是一样的
还可以在line12之间用.then() 空的then方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1.promise.js
/***********情况5********************************/
const Promise = require('./promise');
let p = new Promise((resolve,reject) => {
resolve('hello');
}).then(data=>{
throw new Error('抛出一个错误'); // 不会走自己家的错误
},err=>{
console.log(err)
})
// .catch(err=>{
// console.log('err line10:' ,err);
// })
.then(null,err=>{
console.log('err line15:', err);
})

当cathch后面跟了一个then 还是会走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
// 1.promise.js
const Promise = require('./promise');
let p = new Promise((resolve,reject) => {
resolve('hello');
}).then(data=>{
throw new Error('抛出一个错误'); // 不会走自己家的错误
},err=>{
console.log(err)
})
.catch(err=>{
console.log('err line10:' ,err);
})
.then()
.then(data=>{
console.log("line14---",data);
},err=>{
console.log('err line16:', err);
})
// 执行结果:
/*
err line10: 抛出一个错误
at Promise.then.data (e:\.......js:4:11)
at process._tickCallback (internal/process/next_tick.js:68:7)
at Function.Module.runMain (internal/modules/cjs/loader.js:757:11)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
line14--- undefined
*/

小结:line11-13和line14-16是一样的,相当于catch就是then里面少写了一个成功的方法 是then的语法糖 对应的promise.js

1
2
3
4
// promsie.js
catch(errCallback){ // 加了一个catch方法
return this.then(null, errCallback); // 没有成功的then
}

【12】

1
2
3
4
5
6
7
8
let p = new Promise( (resolve, reject) => {
resolve(123);
}).then(data=>{
console.log(data);
})
Promise.resolve(123).then(data=>{
console.log(data);
})

上面 line1-5 和 line6-8是一样的 resolve是当前类上的静态方法 说白了也是一个语法糖

1
2
3
4
5
6
7
8
9
10
11
// promise.js
static resolve(value){ // 创建了一个成功的promise
return new Promise((resolve, reject)=>{
resolve(value);
})
}
static reject(reason){ // 创建了一个失败的promise
return new Promise((resolve, reject)=>{
reject(reason);
})
}

完整版Promise.js

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
135
136
137
138
139
140
const resolvePromise = (promise2, x, resolve, reject) => { 
if(promise2 === x){
return reject(new TypeError(`Chaining cycle detected for promise #<Promise>`));
}
let called;
if( (typeof x === 'object' && x !== null) || (typeof x === 'function')){
try{
let then = x.then;
if(typeof then === 'function'){

then.call(x, y=>{
//resolve(y);
if(called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, r=>{
if(called) return;
called = true;
reject(r);
})
}else{
resolve(x);
}
}catch(e){
if(called) return;
called = true;
reject(e);
}
}else{
resolve(x);
}
}
class Promise{
constructor(executor){
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
// 2个数组存储
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
// 对value的值做解析
if(value instanceof Promise){
return value.then(resolve, reject ); // 和resolvePromise的功能一样
}
if(this.status === PENDING){
this.value = value;
this.status = FULFILLED;
// 发布
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if(this.status === PENDING){
this.reason = reason;
this.status = REJECTED;
// 发布
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);
}
}

then(onFulfilled, onRejected){
//可选参数 没传就给一个默认参数即可
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val=>val;
onRejected = typeof onRejected === 'function' ? onRejected : err=>{throw err};
let promise2 = new Promise((resolve, reject) => {
if(this.status === FULFILLED){
setTimeout(()=>{
try {
let x = onFulfilled(this.value);
//resolve(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})

}
if(this.status === REJECTED){
setTimeout( ()=>{
try {
let x = onRejected(this.reason);
//reject(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})

}
if(this.status === PENDING){
this.onResolvedCallbacks.push(()=>{
//todo
setTimeout( ()=>{
try {
let x = onFulfilled(this.value);
//resolve(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})

})
this.onRejectedCallbacks.push(()=>{
//todo
setTimeout( ()=>{
try {
let x = onRejected(this.reason);
//reject(x);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
})
}
})
return promise2;
}
catch(errCallback){
return this.then(null, errCallback); // 没有成功的then
}
static resolve(value){ // 创建了一个成功的promise
return new Promise((resolve, reject)=>{
resolve(value);
})
}
static reject(reason){ // 创建了一个失败的promise
return new Promise((resolve, reject)=>{
reject(reason);
})
}
}

拓展

1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let p = new Promise((resolve, reject) => {
resolve();
})
let p1 = p.then(()=>{
}).then(()=>{
})

let p11 = p.then(()=>{
})
p11.then(()=>{
})
console.log(p1, p11, p1 === p11);
// Promise { <pending> } Promise { <pending> } false
// 上面p1和p11不一样
// p1是line4-8这2个then之后的返回结果
// p11是line8-9这个then的返回结果
2) promise 中的链式调用如何中断 ?
1
2
3
4
5
6
7
8
9
let p = new Promise((resolve, reject) => {
resolve();
})
p.then(()=>{
console.log('ok');
}).then(()=>{
console.log('1')
})
// ok 1

现在希望在line5这个then就停止 如下:

1
2
3
4
5
6
7
8
9
10
let p = new Promise((resolve, reject) => {
resolve();
})
p.then(()=>{
console.log('ok');
return new Promise(()=>{}) // 这样就终止了
}).then(()=>{
console.log('1')
})
// ok

总结: 中断promise链 就是返回一个等待的promise

3)finally实现原理
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
Promise.resolve().finally(()=>{
console.log(1);
})
// 1
Promise.reject().finally(()=>{
console.log(1);
})
// 1 报错:UnhandledPromiseRejectionWarning: undefined

/*************************分割线*******************************************/

Promise.reject().finally(()=>{
console.log(1);
}).catch(err=>{
console.log(err);
})// 1 undefined

/*************************分割线*******************************************/

Promise.reject().finally(()=>{
console.log(1);
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve();
},1000);
})
}).catch(err=>{
console.log(err);
})// 1 过了1秒打印 undefined

Promise.reject().finally 因为是这样调用的finally 所以这个finally是实例上的方法不是类上的方法 类上的方法直接Promise.调用

下面自己手下写finally

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Promise.prototype.finally = function(callback){ // 疑问 为什么实例是Promise.prototype
// 因为finally·后面直接跟着.catch 之前有讲过.catch就是.then没有调成功方法.then(null,()=>),
// 所以可以看出finally相当于是一个then方法 不管成功失败都执行
return this.then( val=>{ // 这个this就是实例
callback();
return val; // 如果上一个是成功 就将成功往下传递
}, err=>{
callback();
throw err; // 如果上一个是失败 就将失败往下抛
})
}

Promise.reject().finally(()=>{
console.log(1);
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve();
},1000);
})
}).catch(err=>{
console.log(err);
})
// 但是 如上line15-19这个callback返回的是一个promise
// 1 undefined 结果这个undefined 并没有等待1秒再打印

改进:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Promise.prototype.finally = function(callback){
return this.then( val=>{
// 等待finall中的函数执行完毕 再继续执行
// finally函数可能返回一个promise 用Promise.resolve等待返回的promise执行完
return Promise.resolve(callback()).then(()=>val);
//return val;
}, err=>{
return Promise.resolve(callback()).then(()=>{throw err});
//throw err;
})
}
Promise.reject().finally(()=>{
console.log(1);
return new Promise((resolve, reject)=>{
setTimeout(() => {
resolve();
},1000);
})
}).catch(err=>{
console.log(err);
})// 1 过了1秒打印 undefined

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 4个小示例
// 1)
Promise.resolve(123).finally(()=>{ // #1
console.log('finally');
return new Promise( (resolve, reject) => {
setTimeout( ()=>{
resolve('456');// #2
})
})
}).then(data=>{
console.log('success:',data);
},err=>{
console.log('err::',err)
})
// 替换 #1 #2
// Promise.resolve(123) 这是定时器里的: resolve('456'); 结果:success: 123
// Promise.resolve(123) 这是定时器里的: reject('rej'); 结果:err:: rej
// Promise.reject(123) 这是定时器里的: reject('rej'); 结果:err:: rej
// Promise.reject(123) 这是定时器里的: resolve('456'); 结果:err:: 123

用自己写的finally试验

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
Promise.prototype.finally = function(callback){
return this.then( val=>{
console.log('resolve~~', val);
return Promise.resolve(callback()).then(()=>val); // ***核心
}, err=>{
console.log('reject~~', err)
return Promise.resolve(callback()).then(()=>{throw err}); // ***核心
})
}
Promise.resolve(123).finally(()=>{ // #1
console.log(1);
return new Promise((resolve, reject)=>{
setTimeout(() => { // #2
//resolve(456);
reject('rej');
},1000);
})
}).then(data=>{
console.log('success:',data);
}, err=>{
console.log('err:', err);
})
// 替换 #1 #2
// Promise.resolve(123) 这是定时器里的: resolve('456'); 结果:resolve~~ 123 1 success: 123
// Promise.resolve(123) 这是定时器里的: reject('rej'); 结果:resolve~~ 123 1 err: rej
// Promise.reject(123) 这是定时器里的: reject('rej'); 结果:reject~~ 123 1 err: rej
// Promise.reject(123) 这是定时器里的: resolve('456'); 结果:reject~~ 123 1 err: 123
总结:

finall里面成功就不管 按照上一个then直接的结果返回 如果是失败则走这个失败

分析:

Promise.resolve() 时(成功),如果这里line4 resolve(callback()) 成功, 就直接走后面接的 .then(()=>val); 这里的val是上一个then传过来的值,所以成功时候不改变最终结果 ;如果line4 resolve(callback()) 失败,就走 .then(()=>val) 的失败,因为这里的.then里面没有失败的回调,所以会接着找下面的回调 即line18-22也就是之前的 .catch ,会把 resolve(callback()) 的失败结果输出, 可以在line4 .then(()=>val, (err)=>{console.log(err)}) 打印 resolve(callback()) 失败的结果,那么line18-22,就会走line19 打印 success: undefined 。

Promise.reject() 时(失败),如果这里line7 resolve(callback()) 成功,就直接走后面接的 then(()=>{throw err}),将上一个then的错误传递下去,走line21; 如果line7 resolve(callback()) 失败,就走 .then(()=>{throw err}) 这里没有失败的接受,就走最外面line21 。

4)(待看视频理解 找不到了…)
1
2
3
4
5
6
7
8
9
10
11
12
Promise.resolve().then(console.log('now'));
console.log('next');
//执行结果: now next

new Promise((resolve, reject) => {
// 这里才是 executor
console.log('now')
resolve('hello')
}).then(d => console.log(d))
console.log('next')
// 执行结果: now next hello
//下面这个能理解, 上面这个理解不了

相当于是then的成功回调,then里new 的promise2的executor立即执行,当前状态已经 FULFILLED,然后setTimeout执行的promise2的resolve

5)Promise.race 赛跑 哪个快用哪个
1
2
3
4
5
6
7
8
9
10
11
12
13
let p1 = new Promise( (resolve, reject)=>{
setTimeout(()=>{
resolve('p1 ok');
}, 1000);
})
let p2 = new Promise( (resolve, reject)=>{
setTimeout(()=>{
resolve('p2 ok');
}, 2000);
})
Promise.race([p1, p2]).then(data=>{
console.log('success:', data); //success: p1 ok
});

示例

1
2
3
4
5
6
7
8
9
// Promsie.race
let fs = require('fs').promises;
Promise.race([fs.readFile(__dirname+'/name.txt', 'utf8'), 4,5,6,fs.readFile(__dirname+'/age.txt', 'utf8'),123]).then(data=>{
console.log(data);
},err=>{
console.log(err);
})
// 4 注意:如果这里面读取name.txt的时候是失败的 也能成功读取到4
// 个人理解:如果其中有执行完成的,其他正在执行的还是会继续执行 因为promise是立即执行的,并不会中断

手写一个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
Promise.race = function(promises){
return new Promise( (resolve, reject) =>{
for(let i = 0; i < promises.length; i++){
promises[i].then(resolve,reject); // 这里只要一个成功就成功,一个失败就失败
}
})
}

let p1 = new Promise( (resolve, reject)=>{
setTimeout(()=>{
resolve('p1 ok');
// reject('p1 ok');
}, 1000);
})
let p2 = new Promise( (resolve, reject)=>{
setTimeout(()=>{
resolve('p2 ok');
}, 2000);
})
Promise.race([p1, p2]).then(data=>{
console.log('success:', data); //success: p1 ok
}, err=>{
console.log('err:', err) // err: p1 ok
});

应用场景 :一个网站有个接口 在两个服务器上 谁快用谁

6)题目: 如何放弃某个promise的执行结果?
1
2
3
4
5
6
7
8
9
10
let p = new Promise( (resolve, reject)=>{
setTimeout(()=>{
resolve('ok');
}, 3000);
})

p.then( data=>{
console.log('过三秒之后执行结果:', data);
})
// 这里肯定是过3秒之后返回结果 我希望的是如果过了2秒还没有返回结果就调p.then里面的失败方法

如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function wrap(p1){
let fail = null;
let p2= new Promise( (resolve, reject)=>{
fail = reject; // 将p2里失败的方法暴露出来
})
let p = Promise.race([p1, p2]); // race方法返回的也是promise
p.abort = fail;
return p; // 返回一个promise
}

let p = wrap(new Promise( (resolve, reject)=>{
setTimeout(()=>{
resolve('ok');
}, 3000);
}))
p.abort('error~~'); // 终止
p.then( data=>{
console.log('过三秒之后执行结果:', data);
}, err=>{
console.log('返回错误', err); // 返回错误 error~~
})
7) Promise.try 这个方法现在不支持
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
// 既能捕获同步 也能捕获异步
function fn(){ // 如果函数中抛出了同步错误 要通过try-catch来捕获异常
try {
throw new Error();
} catch (error) {

}

// 这个是异步错误
return new Promise( (resolve, reject) => {
setTimeout(() => {
reject();
}, 3000);
})

}

Promise.try = function(callback){
// 因为后面可以调.catch 所以其实Promise.try返回的是一个promise
return new Promise( (resolve, reject) => {
//callback(); // 这个callback有可能是promsie也有可能不是 所以这里要把它变成promise
// Promise.resolve只能返回一个成功的promise ?有疑问它后面跟的then不是既能捕获成功也能捕获失败,为什么说Promise.resolve只能返回一个成功的promise
return Promise.resolve(callback()).then(resolve, reject);
})
}
Promise.try(fn).catch(err=>{
console.log('err', err);
});
8) Promise.all 全部

处理多个异步并发的问题

1
2
3
4
5
6
7
8
let fs = require('fs').promises; 
// 提供promises这个方法 用了这方法以后 fs上面所有的方法都变成promise的了,所以可以如下这样
fs.readFile(__dirname+'/name.txt', 'utf8').then(data=>{
console.log(data);
})
fs.readFile(__dirname+'/age.txt', 'utf8').then(data=>{
console.log(data);
})

全部完成才算完成 如果有一个失败就失败 Promsie.all是按照顺序执行的

1
2
3
4
5
6
7
let fs = require('fs').promises; 
Promise.all([1, 2, fs.readFile(__dirname+'/name.txt', 'utf8'), 4,5,6,fs.readFile(__dirname+'/age.txt', 'utf8'),123]).then(data=>{
console.log(data);
},err=>{
console.log(err);
})
// [ 1, 2, 'age.txt', 4, 5, 6, '18', 123 ]

手写Promise.all

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
const isPromise = value =>{
if( (typeof value === 'object' && value !== null) || typeof value === 'function'){
return typeof value.then === 'function';
}
}
Promise.all = function(promises){ // 因为Promise.all返回的是结果调用的是then所以这里要返回promise
return new Promise( (resolve, reject) => {
let arr = []; // 存放最终结果的
let i = 0; // 索引
let processData = (index, data) =>{
arr[index] = data;
if(++i === promises){ // 将数据存放到数组中,成功的数量和传入的数量相等时抛出即可
resolve(arr);
}
}
for(let i = 0; i < promises.length; i ++ ){
let current = promises[i]; // 这里要判断current是否为promise
if(isPromise(current)){
current.then(data=>{
processData(i, data);
},reject);
}else{
processData(i, current);
}
}
})
}

ES6中的Promise

catch

1
2
3
4
5
6
7
8
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log(r);
});
// 2
// 1

上面代码中,调用resolve(1)以后,后面的console.log(2)还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

一般来说,调用resolve或reject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而不应该直接写在resolve或reject的后面。所以,最好在它们前面加上return语句,这样就不会有意外。

1
2
3
4
5
new Promise((resolve, reject) => {
return resolve(1);
// 后面的语句不会执行
console.log(2);
})

跟传统的try/catch代码块不同的是,如果没有使用catch()方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。
内部有语法错误,浏览器运行到这一行,会打印出错误提示,但是不会退出进程、终止脚本执行。

Promise.all

注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]

上面代码中,p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。

如果p2没有自己的catch方法,就会调用Promise.all()的catch方法。