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();
- 箭头函数中没有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]
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
里面的成功还是失败函数。
链式调用
- 想走下一个then的失败函数
- 抛出一个异常
- 返回一个失败的promise
.
- 如果then返回一个普通值 会走下一个then的成功,
- 如果then返回promise 就让promise 执行,并采用他的状态判断走下一个then的成功或失败
- 下一个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方法回调是异步的
参考来源珠峰架构!