手写Promise

Promise

高阶函数:
一个函数的参数是一个函数 (回调)
一个函数返回一个函数 (拆分函数)

AOP 面向切片 装饰

把核心抽离出来 在核心基础上增加功能

// 1. 返回一个函数
// 2. ** 函数中先调用传入的增加函数再调用主函数
Function.prototype.before = function(beforeFn){
    return (...args)=>{ // 箭头函数中没有this指向 没有arguments 所以会像上级作用域查找
        beforeFn();
        this(...args); // this指say函数
    }
}

const say = (...args)=>{
    console.log('说话',args);
}
const newSay = say.before(()=>{
    console.log('您好')
})
const newSay1 = say.before(()=>{
    console.log('天气很好')
})
newSay(1,2,3);  //newSay指返回的函数
newSay1();
  1. 箭头函数中没有this指向 没有arguments 都会向上级作用域查找

柯里化

把一个大函数拆分成很多具体功能的函数

//使add封装为可以分批传入任意个数参数的方式调用
const add = (a, b, c, d, e) => {
   return a + b + c + d + e;
};

// ** curring功能--收集参数,判断如果传参不够则返回自身函数下次调用收集,如果传参够了则调用目标函数
const curring = (fn,arr = [])=>{ 
    let len = fn.length; 
    return (...args)=>{
        arr = arr.concat(args);  //收集参数
        if(arr.length < len){  //参数不够递归收集
            return curring(fn,arr);
        }
        return fn(...arr); //参数够了调用目标函数
    }
}
let r = curring(add)(1)(2)(3)(4); // [1,2,3,4,5]
  1. fn.length : 函数的形参个数,无法得知实参个数。

发布订阅模式

订阅时将函数放入数组,发布时遍历数组并调用函数

on(订阅):将订阅事件存入数组中,
emit(发布):遍历调用订阅的(数组中)事件。

const fs = require('fs');

let e = { // events模块   vue $on $once $off
    arr:[],
    on(fn){
        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)
    }
})

let 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(); // 发布
}); 

观察者模式

被观察者将观察者(多个实例)存入数组中,被观察者状态发生变化时遍历数组通知观察者(调用观察者方法)。

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

const p = new Promise((resolve, reject) => {
  // reject('hello');
  // throw Error();
  setTimeout(() => {
    resolve('hello')
  })
})

p.then((data) => {
  console.log(data)
}, (err) => {
  console.log(err)  
})

通过resolve()reject()来改变promise内部状态,从而决定调用then里面的成功还是失败函数。

链式调用

  1. 想走下一个then的失败函数
    1. 抛出一个异常
    2. 返回一个失败的promise
      .
  2. 如果then返回一个普通值 会走下一个then的成功,
  3. 如果then返回promise 就让promise 执行,并采用他的状态判断走下一个then的成功或失败
  4. 下一个then走向只由上一个then决定,下一个then的data是上一个then的返回值
 function readFile(...args){
    return new Promise((resolve,reject)=>{
        fs.readFile(...args,function(err,data){
            if(err)reject(err);
            resolve(data);
        })
    })
}
readFile('./name.txt','utf8').then(data=>{
    return readFile(data,'utf8')
},err=>{
}).then(data=>{
    console.log(data);
},err=>{
    console.log(err);
})

promise简易源码实现

const Promise = require('./promise.js');
const p = new Promise((resolve, reject) => {

  // **同步时先走resove方法,异步时先走then方法
  setTimeout(() => {
    resolve('hello')
  });
  // reject('hello');
  // throw Error();
  
})
// 多次调用
p.then((data) => {
  console.log(data)
}, (err) => {
  console.log(err)  
})
p.then((data) => {
  console.log(data)
}, (err) => {
  console.log(err)  
})

// 链式调用
p.then((data) => {
  console.log(data)
}, (err) => {
  console.log(err)  
})
.then((data) => {
  console.log(data)
}, (err) => {
  console.log(err)  
})
/*
* 1. 第一个then只有抛出错误或反返回失败的paomise,第二个then才会走失败
*/ 
const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";

class Promise{
  constructor(executor) {
    this.state = PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        // 发布 异步时then的订阅
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }
    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    } catch (err) {
      reject(this.reason)
    }
  }
  then(onFulfilled, onRejected) {
    if (this.state === FULFILLED) {
      onFulfilled(this.value);
    }
    if (this.state === REJECTED) {
      onRejected(this.reason);
    }
    if (this.state === PENDING) {
        //订阅 异步时then里的回调
      this.onResolvedCallbacks.push(() => {
        onFulfilled(this.value);
      });
      this.onRejectedCallbacks.push(() => {
        onRejected(this.reason);
      });
    }

  }
}
module.exports = Promise;

promise源码

不包含Promise静态方法

const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
const resolvePromise = (promise2, x, resolve, reject) => {
  /**
   * 如果x为promise,判断x(回调返回的promise)是否为内部默认返回的promise2。
   * 如果是,就会出现死循环。
   * 自己等待自己完成(promise2需要等待then的回调返回的promise状态)。
   * 此时直接返回promise2的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调过成功再调失败
     */
    let called;

    try { // x.then有可能报错
      let then = x.then;
      if (typeof then === 'function') {  /** 就认为是promise了 */
        /** 
         * 判断是走成功还是走失败 
         */
        then.call(x, y => { // 走成功
          if (called) return;
          called = true;

          // resolve(y);
          resolvePromise(promise2, y, resolve, reject); //有可能返回的promise的resolve中又传入promise
        }, r => { // 走失败
          if (called) return;
          called = true;
            
          reject(r);
        })
      } else { /** 不是promise, 常量直接抛出*/ 
        resolve(x);
      }
      
    } catch (err) {
      if (called) return;
      called = true;

      reject(e); // 取then抛出异常就报错好了
    }

  } else { //** 不是promise*/ 
    resolve(x);
  }
}
class Promise{
  constructor(executor) {
    this.state = PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.value = value;
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }
    const reject = (reason) => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    } catch (err) {
      reject(this.reason)
    }
  }
  then(onFulfilled, onRejected) {
    // 如果then的两个回调不是函数或者不传做处理
    onFulfilled = typeof onFulfilled === 'function'?onFulfilled:val=>val;
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
    
    let promise2 = new Promise((resolve, reject) => {
      let x = undefined;
      /**
       * x为上一个then返回值,
       * 上一个then, 1.抛出错误 或 2.返回失败promise,下一个then才走失败 (调用promise2的reject)
       * 否则都走成功(调用promise2的resolve)
       */ 
      try { 
        if (this.state === FULFILLED) {
          x = onFulfilled(this.value);
        }
        if (this.state === REJECTED) {
          x = onRejected(this.reason);
        }
        if (this.state === PENDING) {
          this.onResolvedCallbacks.push(() => {
            x = onFulfilled(this.value);
          });
          this.onRejectedCallbacks.push(() => {
            x = onRejected(this.reason);
          });
        }
        // resolve(x);  

      } catch (err) {  /** 1. 抛出错误走失败(reject)*/ 
        reject(err);
      }
      /** 2. 
       * 判断x是否为失败的promise
       * 如果x是promise,x会决定promise2是resolve还是reject
       */
      setTimeout(() => {  // 为了拿到正在new的promise2做参数,将其放入定时器中
        resolvePromise(promise2, x, resolve, reject); // 
      })
    })
    return promise2;
  }
}
module.exports = Promise;

纠错:

promise源码中:
then函数中的两个回调需要放入异步(setTimeout)中,因为es6的Promise中的then方法回调是异步的


参考来源珠峰架构

posted @ 2019-08-21 16:06  杨旺  阅读(333)  评论(0编辑  收藏  举报