0%

Promise

基本概念

高阶函数

JS 中 函数是一等公民
函数可以作为参数和返回值传递

回调函数的问题

  1. 不能 trycatch
  2. 不能 return
  3. 回调地狱

解决回调地狱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let EventEmitter = require("events");
let eve = new EventEmitter();
let html = {}
eve.on("ready", function(key, value) {
html[key] = value;
if(Object.keys(html).length === 2){
console.log("ok)
}
});

fs.readFile("./node/template.txt", "utf8", function(err, data) {
eve.emit("ready", "template", data);
});
fs.readFile("./node/data.txt", "utf8", function(err, data) {
eve.emit("ready", "data", data);
});

哨兵函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let html = {};
function done(key, value) {
html[key] = value;
if (Object.keys(html).length === 2) {
console.log("ok");
}
}

fs.readFile("./node/template.txt", "utf8", function (err, data) {
done("template", data);
});
fs.readFile("./node/data.txt", "utf8", function (err, data) {
done("data", data);
});

进一步优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function render(length,cb){
return function(key,value){
html[key] = value
if(Object.keys(html).length === length){
cb()
}
}
}
function done = render(2,function(){
console.log("ok")
})

fs.readFile("./node/template.txt", "utf8", function(err, data) {
done("template", data);
});
fs.readFile("./node/data.txt", "utf8", function(err, data) {
done("data", data);
});

generator

生成器是一个函数,可以用来生成迭代器,生成器函数和普通函数不同,生成器函数中间可以暂停

1
2
3
4
5
6
7
8
9
10
11
12
13
async function read(){
let template = await readFile('./template.txt)
let data = await readFile('./data.txt')
return template + data
}
// 等同于
return read(){
return co(function*(){
let template = yield readFile('./template')
let data = yield readFile('./data')
return template + data
})
}

co

1
2
3
4
5
6
7
8
9
10
11
12
13
function co(gen){
let it = gen(); // gen是一个genarator函数
return new Promise((resolve,reject) => {
!function next(lastVal){
if{value,done} = it.next(lastVal);
if(done){
resolve(value);
}else{
value.then(next,reject)
}
}
})
}

Promise 详解

生命周期

Promise 的生命周期,初始为 pending state,表示异步操作尚未结束。挂起状态可以认为是未决的 unsettled,一旦异步操作结束, Promise 就会被认为是 已决的,进入两种可能状态

  • 已完成( fulfilled ): Promise 的异步操作已成功结束;
  • 已拒绝( rejected ): Promise 的异步操作未成功结束,可能是一个错误,或由其他原
    因导致。
    then()方法在所有的 Promise 上都存在,并且接受两个参数。第一个参数是 Promise 被完成时要调用的函数,与异步操作关联的任何附加数据都会被传入这个完成函数。第二个参数则是 Promise 被拒绝时要调用的函数,与完成函数相似,拒绝函数会被传入与拒绝相关联的任何附加数据。用这种方式实现 then() 方法的任何对象都被称为一个 thenable 。所有的 Promise 都是
    thenable ,反之则未必成立。
    Promis 也具有一个 catch() 方法,其行为等同于只传递拒绝处理函数给 then()。

创建未决的 Promise

使用 Promise 构造函数,Promise 执行器被调用的时候立即运行,当 resolve 或 reject 在执行器内部被调用时,一个作业被添加到作业队列,以决议这个 Promise。这和 setTimeout 或 setInterval 类似。

1
2
3
4
5
6
7
8
let promise = new Promise(function (resolve, reject) {
console.log("Promise");
resolve();
});
promise.then(function () {
console.log("Resolved.");
});
console.log("Hi!");

输出:
Promise
Hi!
Resolved

完成处理函数与拒绝处理函数总是会在执行器的操作结束后被添加到作业队列的尾部,所以 then 中的操作会在最后执行。

创建已决的 Promise

使用 Promise.resolve 或者 Promise.reject

1
2
3
4
let promise = Promise.resolve(42);
promise.then(function (value) {
console.log(value); // 42
});

经过我自己的测试,书上内容有误。以下为我自己测试的结果
若传入的 Promise 为挂起态,则 Promise.resolve 调用会将该 Promise 原样返回。此后如果决议原 Promise,在 then() 中可以接收到参数,如果拒绝,可以在 catch 中接收到参数。
Promise.resove 始终会返回原 Promise,而 Promise.reject 始终会对 Promise 重新包装,包装后的 Promise 处于拒绝态,且其 catch 接受的参数是原先处于拒绝态度的 Promise

thenable

当一个对象拥有一个能接受 resolve 与 reject 参数的 then() 方法,该对象就会被认为是一个非 Promise 的 thenable

1
2
3
4
5
6
7
8
9
let thenable = {
then: function (resolve, reject) {
resolve(42);
},
};
let p1 = Promise.resolve(thenable);
p1.then(function (value) {
console.log(value); // 42
});

Promise.resolve 方法会将其转换为 Promise,其状态为 Thenable 的 then 方法返回的状态,而 Promise.reject 方法会始终返回一个 reject 态的 Promise,传递给 catch 的参数为原 Thenable 对象

执行器错误

如果在执行器内部抛出了错误,那么 Promise 的拒绝处理函数就会被调用。

Promise A+ 实现

对照 https://promisesaplus.com/实现就好。

需要注意的规范中的 3.1 注明了 then 中的 onFulfilled and onRejected 需要在本次事件循环结束后方可执行。

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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function Promise(executor) {
let self = this; // 缓存 promise 实例
self.status = PENDING;
self.onResolvedCallbacks = [];
self.onRejectedCallbacks = [];

// 2.1
function resolve(value) {
setTimeout(() => {
if (self.status === PENDING) {
self.status = FULFILLED;
self.value = value;
self.onResolvedCallbacks.forEach((cb) => cb());
}
});
}
function reject(reason) {
setTimeout(() => {
if (self.status === PENDING) {
self.status = REJECTED;
self.value = reason;
self.onRejectedCallbacks.forEach((cb) => cb());
}
});
}
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}

Promise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};

const self = this;
let promise2;
if (self.status === FULFILLED) {
return (promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
});
}));
}
if (self.status === REJECTED) {
return (promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = onRejected(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}));
}
if (self.status === PENDING) {
return (promise2 = new Promise(function (resolve, reject) {
self.onResolvedCallbacks.push(function () {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
self.onRejectedCallbacks.push(function () {
try {
let x = onRejected(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}));
}
};

// 根据 then 的传入处理函数 决定 then 返回的 promise 的状态
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError("Circular reference"));
}
let called = false;
if (x !== null && (typeof x === "object" || typeof x === "function")) {
try {
let then = x.then;
if (typeof then === "function") {
then.call(
x,
function (y) {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
function (err) {
if (called) return;
called = true;
reject(err);
}
);
} else {
if (called) return;
called = true;
resolve(x);
}
} catch (err) {
if (called) return;
called = true;
reject(err);
}
} else {
resolve(x);
}
}

Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
};

Promise.prototype.resolve = function (value) {
new Promise(function (resolve) {
resolve(vzlue);
});
};
Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason);
});
};
Promise.deferred = function () {
let res, rej;
const promise = new Promise((resolve, reject) => {
res = resolve;
rej = reject;
});
return {
promise,
resolve: res,
reject: rej,
};
};

module.exports = Promise;