1、先来个普通版的Promise手写吧~
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class MyPromise {
constructor(executor) {
this.status = Pending;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.status === Pending) {
this.status = Fulfilled;
this.value = value;
this.onResolvedCallbacks.forEach((fn) => fn());
}
};
let reject = (reason) => {
if (this.status === Pending) {
this.status = Rejected;
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
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);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === Rejected) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === Pending) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
catch(errCallback) {
return this.then(null, errCallback);
}
}
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) => {
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);
}
};
测试一下MyPromise:
let promise = new MyPromise((resolve, reject) => {
resolve("成功");
})
.then()
.then()
.then((data) => {
console.log(data);
},
(err) => {
console.log("err", err);
}
)
// 成功
2、添加finally方法:
class MyPromise {
constructor(executor) {
...
}
then(onFulfilled, onRejected) {
...
}
catch(errCallback) {
...
}
finally(fn) {
return this.then(
(value) => {
return MyPromise.resolve(fn()).then(() => value);
},
(err) => {
return MyPromise.reject(fn()).then(() => {
throw err;
});
}
);
}
}
测试finally方法:
MyPromise.resolve(3).finally(()=>{
return new MyPromise((resolve,reject)=>{
setTimeout(() => {
resolve(123)
}, 3000);
})
}).then(data=>{
console.log(data,'success')
}).catch(err=>{
console.log(err,'error')
})
// 3 success
3、添加Mypromise.all方法:
class MyPromise {
constructor(executor) {
...
}
then(onFulfilled, onRejected) {
...
}
catch(errCallback) {
...
}
finally(fn) {
...
}
//all方法-所有的promise的状态变成fulfilled,包装实例才会变成fulfilled, 有一个变成rejected,包装实例就会变成rejected
static all(promises) {
if (!promises.length) return MyPromise.resolve([]);
promises = promises.map((item) =>
item instanceof MyPromise ? item : MyPromise.resolve(item)
);
return new MyPromise((resolve, reject) => {
let result = [];
let count = 0;
for (let i = 0; i < promises.length; i++) {
promises[i]
.then((val) => {
result[i] = val;
count++;
if (count === promises.length) {
resolve(result);
}
})
.catch((e) => {
reject(e);
});
}
});
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value);
});
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
}
测试MyPromise.all方法:
let p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("ok1");
}, 1000);
});
let p2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("ok2");
}, 2000);
});
MyPromise.all([1,2,p1,p2]).then(
(data) => {
console.log("mypromise resolve", data);
},
(err) => {
console.log("mypromise reject", err);
}
);
Promise.all([1,2,p1,p2]).then(
(data) => {
console.log("promise resolve", data);
},
(err) => {
console.log("promise reject", err);
}
);
// promise resolve [ 1, 2, 'ok1', 'ok2' ]
// mypromise resolve [ 1, 2, 'ok1', 'ok2' ]
4、添加MyPromise.allSettled方法:
class MyPromise {
constructor(executor) {
...
}
then(onFulfilled, onRejected) {
...
}
catch(errCallback) {
...
}
finally(fn) {
...
}
static all(promises) {
...
}
//allSettled方法-所有状态改变,不管是fulfilled还是rejected, 包装实例都会变成fulfilled
static allSettled(promises) {
if (!promises.length) {
throw Error("不能为空");
}
promises = promises.map((item) =>
item instanceof MyPromise ? item : MyPromise.resolve(item)
);
return new MyPromise((resolve, reject) => {
let result = [];
let count = promises.length;
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(val) => {
result[i] = {
status: Fulfilled,
value: val,
};
count -= 1;
if (count === 0) {
resolve(result);
}
},
(err) => {
result[i] = {
status: Rejected,
reason: err,
};
count -= 1;
if (count === 0) {
resolve(result);
}
}
);
}
});
}
}
测试MyPromise.allSSettled方法:
let p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("ok1");
}, 1000);
});
let p2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject("ok2");
}, 2000);
});
MyPromise.allSettled([1,2,p1,p2]).then((res) => {
console.log('mypromise',res);
})
Promise.allSettled([1,2,p1,p2]).then((res) => {
console.log('promise',res);
})
// promise [
// { status: 'fulfilled', value: 1 },
// { status: 'fulfilled', value: 2 },
// { status: 'fulfilled', value: 'ok1' },
// { status: 'rejected', reason: 'ok2' }
//]
// mypromise [
// { status: 'Fulfilled', value: 1 },
// { status: 'Fulfilled', value: 2 },
// { status: 'Fulfilled', value: 'ok1' },
// { status: 'Rejected', reason: 'ok2' }
//]
5、添加MyPromise.race方法:
class MyPromise {
constructor(executor) {
...
}
then(onFulfilled, onRejected) {
...
}
catch(errCallback) {
...
}
finally(fn) {
...
}
static all(promises) {
...
}
static allSettled(promises) {
...
}
// race方法-其中一个状态改变,不论成功或者失败,最终状态会由最先改变状态的那个promise的状态决定
static race(promises) {
promises.map((item) =>
item instanceof MyPromise ? item : MyPromise.resolve(item)
);
return new MyPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
});
}
}
测试MyPromise.race方法:
let p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("ok1");
}, 1000);
});
let p2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject("ok2");
}, 800);
});
MyPromise.race([p1, p2]).then(res=>{
console.log('myPromise----',res);
}).catch(err=>{
console.log('myPromise----',err);
})
Promise.race([p1, p2]).then(res=>{
console.log('promise--',res);
}).catch(err=>{
console.log('promise---',err);
})
// promise--- ok2
// myPromise---- ok2
6、添加MyPromise.any方法:
class MyPromise {
constructor(executor) {
...
}
then(onFulfilled, onRejected) {
...
}
catch(errCallback) {
...
}
finally(fn) {
...
}
static all(promises) {
...
}
static allSettled(promises) {
...
}
static race(promises) {
...
}
// any方法,有一个变成fulfilled状态,包装实例就会变成fulfilled状态,当所有的状态变成rejected,包装实例才会变成rejected
static any(promises) {
return new MyPromise((resolve, reject) => {
let count = promises.length;
let errs = [];
if (count === 0) reject("all promises rejected");
promises = promises.map((item) =>
item instanceof MyPromise ? item : MyPromise.resolve(item)
);
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(res) => {
resolve(res);
},
(err) => {
errs[i] = err;
count -= 1;
if (count === 0) {
reject(errs);
}
}
);
}
});
}
}
测试MyPromise.any方法:
let p3 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("ok1");
}, 1000);
});
let p4 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject("ok2");
}, 1000);
});
MyPromise.any([1,2,p3,p4])
.then((res) => {
console.log("mypromise 成功", res);
})
.catch((err) => {
console.log("mypromise 失败", err);
});
Promise.any([1,2,p3,p4])
.then((res) => {
console.log("promise 成功1", res);
})
.catch((err) => {
console.log("promise 失败1", err);
});
// promise 成功1 1
// mypromise 成功 1
7、Promise不会中断,如果想要Promise执行过程中中断,可以利用race方法包装一下
function wrap(promise) {
let abort;
let newPromise = new MyPromise((resolve, reject) => {
abort = reject;
});
let p = MyPromise.race([promise, newPromise]);
p.abort = abort;
return p;
}
let promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("成功的");
}, 3000);
});
let newPromise = wrap(promise);
setTimeout(() => {
newPromise.abort("超时了");
}, 1000);
newPromise
.then((res) => {
console.log("成功---", res);
})
.catch((err) => {
console.log("失败---", err);
});
// 失败--- 超时了
8、将node 的API转换成一个接收相同的方法并且可以和then结合使用的工具函数:
import fs from "fs";
// util.promisify() 的简化实现。不包括所有情况,不要在 prod 环境中使用此选项!
function promisify(fn) {
return function (args) {
return new Promise((resolve, reject) => {
fn.apply(this, [].concat(args).concat([(err, res) => {
if (err != null) {
return reject(err);
}
resolve(res);
}
])
);
});
};
}
// 将 fs.readFile() 转换为一个接受相同参数但返回 Promise 的函数。
const readFile = promisify(fs.readFile);
// 现在可以将 readFile() 与 then 一起使用!
readFile("./package.json").then(buf=>{
const obj = JSON.parse(buf.toString("utf8"));
console.log(obj.name);
})
// handwritten-code