一.Promise.race 原理
1.实现原理
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
let currentVal = promises[i];
if (currentVal && typeof currentVal.then == "function") {
currentVal.then(resolve, reject);
} else {
resolve(currentVal);
}
}
});
};
race 只采用第一个成功或者失败的结果
2.应用场景 (超时处理)
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("成功");
}, 3000);
});
function wrap(p) {
let abort;
let p1 = new Promise((resolve, reject) => {
abort = reject;
});
let newPromise = Promise.race([p1, p]);
newPromise.abort = abort;
return newPromise;
}
let p1 = wrap(p);
p1.then(
(data) => {
console.log("success", data);
},
(err) => {
console.log("error", err);
}
);
setTimeout(() => {
p1.abort("超过2s了");
}, 2000);
借助 race 的特点,可以实现立即中断 promise 变为失败态。常用作超时操作
二.promisify 原理
const fs = require("fs");
const path = require("path");
function promisify(fn) {
return function (...args) {
return new Promise((resolve, reject) => {
fn(...args, function (err, data) {
if (err) reject();
resolve(data);
});
});
};
}
let read = promisify(fs.readFile);
read(path.resolve(__dirname, "name.txt"), "utf8").then((data) => {
console.log("data", data);
});
三.Promise.all 原理
全部成功才成功,有一个失败就失败,成功的结果是按照调用的顺序来返回的
Promise.all = function (values) {
// 计数器
let ret = []; // 最终返回的结果
let len = values.length;
return new Promise((resolve, reject) => {
values.forEach((val, idx) => {
Promise.resolve(val).then((data) => {
ret[idx] = data; // 没成功一个和索引对应上
if (--len === 0) {
resolve(ret);
}
}, reject); // reject => () => {reject()} // 任何一个promise失败嘞 直接就调用外层promise的失败
});
});
};
Promise.all([
// 全部成功才成功,有一个失败就失败,成功的结果是按照调用的顺序来返回的
fs.readFile(path.resolve(__dirname, "name.txt"), "utf8"),
fs.readFile(path.resolve(__dirname, "age.txt"), "utf8"),
123,
])
.catch((err) => {
console.log(err, "err");
})
.then((data) => {
console.log(data);
});
// [ 'zf', '18', 123 ]
四. Promise.finally 原理
就是 then,特点就是无论成功还是失败都会执行的方法
Promise.prototype.finally = function (fn) {
return this.then(
(data) => Promise.resolve(fn()).then(() => data),
// then中的方法 会等待返回的promise执行完毕后继续执行
// Promise.resolve 要等待fn()执行后的promise执行完毕
(err) =>
Promise.resolve(fn()).then(() => {
throw err;
})
);
};
Promise.reject("ok")
.finally(() => {
// 就是then 特点就是无论成功还是失败都会执行的方法
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("finally");
resolve();
}, 1000);
});
})
.then((data) => {
console.log("成功", data);
})
.catch((err) => {
console.log("失败", err);
});
// finally; 失败 ok
五.generator 使用
1.遍历器的基本实现
const interable = { 0: "a", 1: "b", 2: "c", length: 3 };
interable[Symbol.iterator] = function () {
let index = 0;
return {
// 遍历器对象
next: () => {
return { value: this[index], done: index++ == this.length };
},
};
};
console.log(Array.from(interable)); // ["a", "b", "c"]
如果我们自己去迭代一个对象需要实现一个迭代器接口,自己返回一个具有 next 方法的对象。内部会调用这个 next 方法返回结果包含 value 和 done,当 done 为 true 时迭代完成
2.通过生成器实现
const iterable = { 0: "a", 1: "b", 2: "c", length: 3 };
iterable[Symbol.iterator] = function* () {
let index = 0;
while (index !== this.length) {
yield this[index++];
}
};
console.log([...iterable]); // [ 'a', 'b', 'c' ]
3.生成器使用
const fs = require("fs/promises");
const path = require("path");
function* readFile() {
try {
let data = yield "name.txt";
let name = yield fs.readFile(path.resolve(__dirname, data), "utf8");
return name;
} catch (e) {
console.log(e, "读取出错");
}
}
function co(it) {
return new Promise((resolve, reject) => {
// 递归回调
function next(data) {
// 异步递归处理
let { value, done } = it.next(data);
if (!done) {
Promise.resolve(value).then((data) => {
// => Promise.resolve(value).then(data => next(data))
next(data);
});
} else {
resolve(value); // 整个geneator执行完毕了 结束
}
}
next(); // koa express
});
}
co(readFile()).then((data) => {
console.log(data);
});
这里我们主是掌握思想,异步迭代的思想。(产生一个迭代函数,当做回调函数使用) promise 链式调用; generator + promise + co; async + await;