手写Promise原理
1.函数应用
1.callback/1.js
// 高阶函数
// 一个函数的参数 是一个函数 (回调)
// 一个函数 返回一个函数 (拆分函数)
// 函数的before
// 希望将核心的逻辑提取出来 ,在外面在增加功能
// 重写原型上的方法
// 不会原型
// js的核心 是回调
Function.prototype.before = function(beforeFn){
return (...args)=>{ // 箭头函数中没有this指向 没有arguments 所以会像上级作用域查找
beforeFn();
this(...args); // 展开运算符 say(1,2,3)
}
}
// AOP 切片 装饰 把核心抽离出来 在核心基础上增加功能
const say = (...args)=>{ // 剩余运算符把所有的参数组成一个数组
console.log('说话',args);
}
const newSay = say.before(()=>{
console.log('您好')
})
const newSay1 = say.before(()=>{
console.log('天气很好')
})
newSay(1,2,3);
newSay1();
// react 事务的改变 可以在前面和后面 同时增加方法
1.callback/2.transcation.js
// 事务 开始的时候 做某件事 结束的时候在做某件事 react中的核心逻辑
const perform = (anymethod,wrappers)=>{
wrappers.forEach(wrap=>{
wrap.initilizae();
})
anymethod();
wrappers.forEach(wrap=>{
wrap.close();
})
}
perform(()=>{
console.log('说话')
},[
{ // warpper
initilizae(){
console.log('您好')
},
close(){
console.log('再见')
}
},
{ // warpper
initilizae(){
console.log('您好1')
},
close(){
console.log('再见2')
}
}
])
// 柯里化 我们可以把一个大函数拆分成很多的具体的功能
1.callback/3.curry.js => 面试很可能问到
// 柯里化 : 就是将一个函数拆分成多个函数
// 判断类型 Object.prototype.toString.call
// 高阶函数中包含 柯里化 可以保留参数 bind
const checkType = type => {
return content => {
return Object.prototype.toString.call(content) === `[object ${type}]`;
};
};
// 闭包
let types = ["Number", "String", "Boolean"];
let utils = {};
types.forEach(type => {
utils["is" + type] = checkType(type);
});
console.log(utils.isString("123"));
console.log(utils.isNumber("456"));
// 函数柯里化怎么实现
// 通用的柯里化
// const add = (a, b, c, d, e) => {
// return a + b + c + d + e;
// };
const curring = (fn,arr = [])=>{
let len = fn.length // 这里需要明白fn.length代表的就是函数参数的数量
return (...args)=>{
arr = arr.concat(args); // [1] [1,2,3] < 5
if(arr.length < len){
return curring(fn,arr)
}
return fn(...arr)
}
}
let r = curring(add)(1)(2)(3)(4); // [1,2,3,4,5]
// console.log(r);
const checkType = (type, content) => {
return Object.prototype.toString.call(content) === `[object ${type}]`;
};
let types = ["Number", "String", "Boolean"];
let utils = {};
types.forEach(type => {
utils["is" + type] = curring(checkType)(type); // 先传入一个参数
});
console.log(utils.isString('hello'));
// after 在...之后
1.callback/4.after
const after = (times, fn) => { // after可以生成新的函数 等待函数执行次数达到我的预期时执行
return ()=>{
if(--times === 0){
fn();
}
}
};
let newAfter = after(3, () => {
console.log("三次后调用");
});
newAfter();
newAfter();
newAfter();
// lodash after
// 并发的问题 发布订阅 观察者模式
2.Promise
1.callback/5.all.js
// 1) 我们希望 读取数据 node 异步 会等待同步代码都执行完成后在执行
const fs = require('fs');
let school = {}
// 并发的问题 如何解决 计数器
const after = (times, fn) =>()=> --times === 0 && fn();
let newAfter = after(2, () => {
console.log(school);
});
fs.readFile('name.txt','utf8',(err,data)=>{
school['name'] = data;
newAfter();
});
fs.readFile('age.txt','utf8',(err,data)=>{
school['age'] = data;
newAfter();
});
1.callback/6.on-emit.js
// 发布订阅模式
const fs = require('fs');
let school = {}
let e = { // events模块 vue $on $once $off
arr:[],
on(fn){ // [fn1,fn2]
this.arr.push(fn); // redux
},
emit(){
this.arr.forEach(fn => fn());
}
}
e.on(()=>{ // 订阅
console.log('ok')
})
e.on(()=>{ // 订阅
if(Object.keys(school).length === 2){
console.log(school)
}
})
fs.readFile('name.txt','utf8',(err,data)=>{
school['name'] = data;
e.emit(); // 发布
});
fs.readFile('age.txt','utf8',(err,data)=>{
school['age'] = data;
e.emit();
});
// 发布订阅是观察者的一部分
// 发布订阅模式 => 观察者模式 (vue watcher)
// 发布订阅模式没有关系的
// 观察者模式 我加小宝宝 心情好
1.callback/7.observer.js
class Subject { // 被观察者 小宝宝
constructor(){
this.arr = []; // [o1,o2]
this.state = '我很开心'
}
attach(o){ // 原型上的方法
this.arr.push(o);
}
setState(newState){
this.state = newState;
this.arr.forEach(o=>o.update(newState))
}
}
//观察者模式包含发布订阅
class Observer{ // 观察者 我 我媳妇
constructor(name){
this.name = name
}
update(newState){
console.log(this.name + '小宝宝:'+newState)
}
}
let s = new Subject('小宝宝'); // 小宝宝
let o1 = new Observer('我');
let o2 = new Observer('我媳妇')
s.attach(o1);
s.attach(o2);
s.setState('不开心了');
- promise.js 源码
// resolve会等待,但是reject不会等待
const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
// Object.defineProperty(x,'then',{
// get(){
// throw new Error();
// }
// })
// promise的处理函数
const resolvePromise = (promise2, x, resolve, reject) => {
// 处理x 的类型 来决定是调用resolve还是reject
// 必须要写的很严谨
if(promise2 === x){ // 自己等待自己完成
return reject(new TypeError(`Chaining cycle detected for promise #<Promise>`));
}
// 判断x 是不是一个普通值 先认为你是一个promise
if((typeof x === 'object' && x!==null) || typeof x ==='function'){
// 可能是promise 如何是不是promise then
let called; // 默认没有调用成功 和失败
try{ // 取then的时候,可能会发生异常, 举例是getter里面报错
let then = x.then; // 看一看有没then方法 , 即使是空数据,[].then = undefined
if(typeof then === 'function'){ // {then:function(){}}
// 是promise了
// x.then(()=>{},y=>{}) 会再去取then方法
then.call(x,y=>{ // 如果是一个promise 就用采用这个promise的结果
// y 有可能还是一个promise 实现递归解析
if(called) return // 防止多次调用, 前提是promise对象
called = true // y可能还是promise
resolvePromise(promise2,y,resolve,reject)
},r=>{
if(called) return; // 防止多次调用
called = true
reject(r) // 对于reject为什么不使用resolvePromise,是因为promise不想处理reject的,直接将报错的信息传递出去
})
}else{ // [1,2,3]
resolve(x); // 常量直接抛出去即可 这个不是promise对象
}
}catch(e){
if(called) return; // 防止多次调用
called = true
reject(e); // 取then抛出异常就 报错好了
}
}else{
// 不是promise
resolve(x);
}
};
class Promise {
constructor(executor) {
this.value = undefined;
this.reason = undefined;
this.status = PENDING;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if(value instanceof Promise){ // 但是对于reject,一旦抛出就是不处理,直接传啥返回啥
// 举例出现情况 new Promise((resolve,reject)=>{resolve(new 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());
}
};
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};
// then方法调用后应该返还一个新的promise
let promise2 = new Promise((resolve, reject) => {
// 应该在返回的promise中 取到上一次的状态 来决定这个promise2是成功还是失败
if (this.status === FULFILLED) {
// 当前onFulfilled,onRejected不能再当前的上下文中执行,为了确保代码promise2存在
setTimeout(() => {
try {
// 让then中的方法执行 拿到他的返回值
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.status === PENDING) {
// 举例出现情况 new Promise((resolve,reject)=>{setTimeout(function(){resolve('111')},1000)})
this.onResolvedCallbacks.push(() => {
// todo ....
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
});
return promise2;
}
catch(errCallback){ // 没有成功的then
return this.then(null,errCallback)
}
static reject(reason){ // 创建了一个失败的promise
return new Promise((resolve,reject)=>{
reject(reason);
})
}
static resolve(value){ // 创建了一个成功的promise
return new Promise((resolve,reject)=>{
resolve(value);
})
}
}
Promise.deferred = function(){
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject
})
return dfd;
}
module.exports = Promise;
// 先全局安装 在进行测试 promises-aplus-tests 文件名
// https://github.com/promises-aplus/promises-tests
let p = new Promise((resolve,reject) => {
resolve();
})
p.then(data => {}) // 看出来了p就只是创建了一个实例的作用
=> 等效于 Promise.resolve().then(data => {})
// promise.finally 最终的 无路如何都执行 如果返回一个promise 会等待这个promise执行完成
// Promise.try() ? 可以捕获同步异常和异步异常
Promise.resolve(123).finally(()=>{
console.log('finally');
return new Promise((resolve,reject)=>{
setTimeout(()=>{resolve()},3000)
})
}).then(err=>{
console.log(err)
})
// finally 3秒后打印出123
//========================
Promise.resolve(123).finally(()=>{
console.log('finally');
}).then(err=>{
console.log(err)
})
// finally 123
//=======================
Promise.reject(123).finally(()=>{
console.log('finally');
}).catch(err=>{
console.log(err)
})
// finally 123
// 错误,自己调用自己的例子
const p= new Promise((resolve) => {
resolve(1);
})
const p1 = p.then((res) => {
console.log("res", res);
return p1
})
- 3.promise-all.js
// promise.all 全部 处理多个异步的并发问题
let fs = require('fs').promises; // fs就是一个promise的对象了
// 全部完成才算完成 如果有一个失败 就失败
// Promise.all 是按照顺序执行的 Promise.race
const isPromise = value=>{
if((typeof value === 'object' && value !== null) || typeof value === 'function'){
return typeof value.then === 'function';
}
return false;
}
Promise.all = function(promises){
return new Promise((resolve,reject)=>{
let arr = []; // 存放最终结果的
let i = 0;
let processData = (index,data)=>{
arr[index] = data; // 将数据放到数组中,成功的数量和传入的数量相等的时候 将结果抛出去即可
if(++i === promises.length){ // 注意这里不能是arr.length === promises.length 因为数组里面前面几项都是异步,只有最后一项先成功,那么arr= [empty,empty,1]
resolve(arr)
}
}
for(let i = 0 ;i < promises.length ;i++ ){
let current = promises[i]; // 获取当前的每一项
if(isPromise(current)){ // 如果是promise 。。..
current.then(data=>{
processData(i,data)
},reject)
}else{
processData(i,current)
}
}
})
}
// race 有一个成功就成功 有一个失败就失败
Promise.race([fs.readFile('./name.txt','utf8'),fs.readFile('./age.txt','utf8'),1])
.then(data=>{
console.log(data);
},err=>{
console.log(err);
});
// 1 因为race也是按照顺序依次执行,fs.readFile是异步的,到了1是成功的所以就是成功了
5.async-await
- 4.generator.js
// 生成器 生成迭代器的 es6语法
// async + await
// redux-saga
// 返回值叫迭代器
// function * read(){
// yield 1; //产出
// yield 2;
// yield 3
// }
// // iterator 迭代器
// let it = read();
// console.log(it.next()); // {value:1,done:false}
// console.log(it.next());
// console.log(it.next());
// console.log(it.next()); // return unefined
// 将类数组转化成数组
// 类数组的定义 : 1索引 2.长度
function add() {
// ... for of 必须要给当前对象 提供一个生成器方法
console.log([ // ... Array.from
...{
0: 1,
1: 2,
2: 3,
length: 3,
[Symbol.iterator]:function *(){
let index = 0;
while(index !== this.length){
yield this[index++];
}
}
// [Symbol.iterator]() {
// let len = this.length;
// let index = 0;
// // 迭代器 是有next方法 而且方法执行后 需要返回 value,done
// return {
// next: () => {
// return { value: this[index++], done: index === len + 1 };
// }
// };
// }
}
]);
}
add(1, 2, 3, 4, 5);
// function * read(){
// try{
// let a = yield 1;
// console.log(a)
// let b = yield 2;
// console.log(b)
// let c = yield 3;
// console.log(c)
// }catch(e){
// console.log('e:'+e);
// }
// }
// let it = read();
// console.log(it.next('xxx')) // {value:1.done:false} 第一次next参数没有任何意义
// it.throw('xxx')
const fs = require('fs').promises;
function * read(){
let content = yield fs.readFile('./name.txt','utf8'); // age.txt
let age = yield fs.readFile(content,'utf8'); // 10
let xx = yield {age:age + 10}
return xx;
}
function co(it){
return new Promise((resolve,reject)=>{
// 异步迭代需要先提供一个next方法
function next(data){
let {value,done} = it.next(data);
if(!done){
Promise.resolve(value).then(data=>{
next(data);
},err=>{
reject(err);
})
}else{
resolve(value);
}
}
next();
})
}
// let co = require('co');
co(read()).then(data=>{
console.log(data);
});
// let it = read();
// it.next().value.then(data=>{
// it.next(data).value.then(data=>{
// let r = it.next(data);
// console.log(r.value);
// })
// })
const fs = require('fs').promises;
// async + await 其实是 generator + co的语法糖
async function read(){ // async函数返回的是promise
let r = await Promise.all([p1,p2])
try{
let content = await fs.readFile('./name1.txt','utf8'); // age.txt
let age = await fs.readFile(content,'utf8'); // 10
let xx = await {age:age + 10}
return xx;
}catch(e){
console.log(e);
}
}
read().then(data=>{
console.log(data);
},err=>{
console.log(err);
})
// 实现
// 1) promise.finally
// 2) Promise.try 这个方法 原生里没有
// 3) Promise.race 谁快 用谁
// 4) 如果终止一个promise 不要要当前这个promise结果
// 5) 如果中断promise链