手写promise

221 阅读7分钟

手写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链