乐趣区

关于javascript:手写一个-promise

筹备工作

实现一个高阶函数

调用一个办法,在这个办法执行前先执行另一个办法

// AOP  切片编程
function say(who){console.log(who + '谈话了');
}
// 在函数的原型对象上增加一个属性 berfor 能够让每个函数都能调用
Function.prototype.berfor = function(berforFunc){return (...agrs)=>{berforFunc()
        this(...agrs)
    }
}

let newFn = say.berfor(function(){console.log('谈话之前');
})
newFn('我')

// ======================================================

let oldPush = Array.prototype.push;

function push(...agrs){
    // this ===》arr
    console.log('数据更新了');
    oldPush.call(this,...agrs);  // call 1、扭转 this 指向  2、让函数执行
}

let arr = [1,2,3]
// push(arr,4,5,6)   // 在这调用 push 办法时,this 的指向是全局,所以应用 call  扭转 this 指向
push.call(arr,4,5,6)   // 在这调用 push 办法时,this 的指向是全局,对应的函数外部也是全副,所以应用 call  扭转 this 指向
console.log(arr)

AOP

AOP(面向切面编程)的次要作用是把一些跟外围业务逻辑模块无关的性能抽离进去,其实就是给函数加一层,不必管函数外部实现

成果代码:

function perform(anyMethod,wrappers){return function(){wrappers.forEach(wrapper => wrapper.initialize())
        anyMethod()
        wrappers.forEach(wrapper => wrapper.close())
    }
}
let newFn1 = perform(function(){console.log('say')
},[{initialize(){console.log('wrapper1 beforeSay')
        },
        close(){console.log('wrapper1 close')
        }
    },
    {initialize(){console.log('wrapper2 beforeSay')
        },
        close(){console.log('wrapper2 close')
        }
    }
])

newFn1()
// wrapper1 beforeSay
// wrapper2 beforeSay
// say
// wrapper1 close
// wrapper2 close

after 在。。。之后

// 利用闭包  保留 times  在执行两次后才会输入
function after(times,callback){return function(){if(--times === 0){callback()
        }
    }
}

let fn = after(2, function(){console.log('really')
})
fn();
fn();

应用高阶函数解决异步问题的思路

let fs = require('fs')
fs.readFile('./name.txt','utf8',function(err,res){// console.log(res)
    // 第一种办法应用
    school.name = res
    out() 
    // 第二种办法应用
    out('name',res)
})
fs.readFile('./age.txt','utf8',function(err,res){// console.log(res)
    // 第一种办法应用
    school.age = res
    out()
    // 第二种办法应用
    out('name',res)
})

// 第一种 应用回调函数的办法  然而这个办法 会导致 school 裸露再里面  
// 都能够批改 school,所哟并不是黑号
let school = {}
function out(){console.log(Object.keys(school))
    if(Object.keys(school).length == 2){console.log(school)
    }
}

// 第二种 应用 上述 after 的办法来实现,,也就是闭包的模式
let out = after(2, function(res){console.log(res)
})

function after(times,callback){let school = {}
    return function(key,val){school[key] = val
        if(--times === 0){callback(school)
        }
    }
}

公布模式和订阅模式

let fs = require('fs')
fs.readFile('./name.txt','utf8',function(err,res){
    school.name = res
    event.emit()})
fs.readFile('./age.txt','utf8',function(err,res){
    school.age = res
    event.emit()})
let event = {_arr:[],
    // 订阅
    on:function(fn){this._arr.push(fn)  
    },
    // 公布
    emit:function(fn){this._arr.forEach(fn => fn())
    }
}
let school = {}
event.on(function(){console.log('读取一个');
})
event.on(function(){if(Object.keys(school).length == 2){console.log(school)
    }
})

观察者模式 是基于公布订阅模式的

// 被观察者
class Subject{constructor(){
        this.state = '开心'
        this.arr = []}
    // 增加观察者
    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 sub = new Subject('小宝宝')
let my = new Observer('我')
sub.attach(my)
sub.setState('不开心')
sub.setState('很开心')

开始 promise

promise 优缺点

  • 长处

    • 能够解决异步嵌套问题
    • 能够解决多个异步并发问题
  • 毛病

    • promise 基于回调 会不停的写函数
    • 无奈终止异步

    根本实现 与 then 办法

/**
 * 1、(then 中传递的函数)判断胜利和失败函数的返回后果
 * 2、判断是不是 promise 如果是 promise 就采纳他的状态
 * 3、如果不是 promise 间接将后果传递上来即可
 */
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
// 因为 promise 
const resolvePromise = (_promise, x, fulfill, reject) => {
    let called;
    // x 和 promise 不能是同一个 promise mdn 中有解释  将会进入死循环 (promise 标准)
    if (x === _promise) {return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (typeof x === 'object' && x !== null || typeof x === 'function') {
        try {
            let then = x.then // 取 then 有可能 then 属性是通过 defineProperty 来定义的
            if (typeof then === 'function') {  // 当 then 是一个办法 就认为是 promise 
                then.call(x, y => {if(called) return;
                    called = true
                    resolvePromise(_promise, y, fulfill, reject)   // 参用 promise 的胜利后果向下传 递归  晓得解析进去的是一个一般值
                }, r => {if(called) return;
                    called = true
                    reject(r)    // 采纳失败后果向下传
                }) // 能保障不必再次 then 的值
            } else {fulfill(then) // 阐明 x 是一个一般对象
            }
        } catch (e) {if(called) return;
            called = true
            reject(e) 
        }
    } else {fulfill(x)
    }
}
class MyPromise {
    // 1 看属性是否再原型上
    // 2 看属性是否专用
    constructor(executor) {
        this.status = PENDING
        this.value = undefined;
        this.reason = undefined;
        this.onFulfilledCallbacks = []; // 胜利的函数数组
        this.onRejectedCallbacks = []; // 失败的函数数组

        // 胜利函数
        let fulfill = (value) => {if (this.status === PENDING) {   // 屏蔽
                this.value = value
                this.status = FULFILLED
                this.onFulfilledCallbacks.forEach(fn => fn())
            }
        }

        // 失败函数
        let reject = (reason) => {console.log('reason:' + reason)
            if (this.status === PENDING) {   // 屏蔽
                this.reason = reason
                this.status = REJECTED
                this.onRejectedCallbacks.forEach(fn => fn())
            }
        }

        try {executor(fulfill, reject); // 默认执行器会立即执行
        } catch (e) {reject(e)  // 如果执行失败产生谬误  等价于调用了
        }
    }

    // 传入两个参数   
    then(onFulfilled = data => data, onRejected) {onRejected = typeof onRejected == 'function'? onRejected: err=>{throw err}
        let _promise = new MyPromise((fulfill, reject) => {    // 实现 then 可能链式调用  返回一个本人的实例
            if (this.status === FULFILLED) {setTimeout(() => {  // 为了可能使_promise 实例化实现 所以应用 setTimeout 等 new 完之后执行 setTimeout
                    try {let x = onFulfilled(this.value)
                        // x 可能是一般值 有可能是 promise
                        // 判断 x 的值 => promise2 的状态
                        resolvePromise(_promise, x, fulfill, reject)
                        // fulfill(x)
                    } catch (e) {reject(e)
                    }
                }, 0)

            }
            if (this.status === REJECTED) {setTimeout(() => {
                    try {let x = onRejected(this.reason)
                        resolvePromise(_promise, x, fulfill, reject)
                    } catch (e) {reject(e)
                    }
                }, 0)

            }
            if (this.status == PENDING) {
                // 如果是异步   
                this.onFulfilledCallbacks.push(() => {setTimeout(() => {
                        try {let x = onFulfilled(this.value)
                            resolvePromise(_promise, x, fulfill, reject)
                        } catch (e) {reject(e)
                        }
                    }, 0)

                })
                this.onRejectedCallbacks.push(() => {setTimeout(() => {
                        try {let x = onRejected(this.reason)
                            resolvePromise(_promise, x, fulfill, reject)
                        } catch (e) {reject(e)
                        }
                    }, 0)

                })
            }
        })
        return _promise
    }
}

// 提早对象
MyPromise.defer = MyPromise.deferred = function(){let dfd = {}
    dfd.promise = new MyPromise((resolve,reject)=>{
        dfd.resolve = resolve
        dfd.reject = reject
    })
    return dfd
}

module.exports = MyPromise

let p = new MyPromise((resolve, reject) => {resolve(100)
})

// let promise2 = p.then(data => {//     return new MyPromise((resolve, reject) => {//         setTimeout(() => {//             reject('hello')
//         }, 0)
//     })
// })
// promise2.then(data => {//     console.log('data:' + data)
// }, err => {//     console.log('err:' + err)
// })
// p.then().then().then().then(data=>{//     console.log(data)
// })

// MyPromise.defer() 能够帮忙解决封装嵌套的问题
let fs = require('fs')
function read(url){let dfd = MyPromise.defer()
    fs.readFile(url,'utf8',function(err,res){if(err)  dfd.reject(err)
        dfd.resolve(res)
    })
    return dfd.promise
}

read('./name.txt').then(res=>{console.log(res)
})

实现 promise.all() 办法(一种实现办法)

/**
 * promise.all() 全副 能够实现期待所有的异步执行完后  拿到对立的后果
 * 解决异步并发 同步处理结果
 */

let MyPromise = require('./promise_then')  // 本人封装的 promise 

let fs = require('fs')
function read(url) {let dfd = MyPromise.defer()
    fs.readFile(url, 'utf8', function (err, res) {if (err) dfd.reject(err)
        dfd.resolve(res)
    })
    return dfd.promise
}
const isPromise = (val) => {if ((typeof val == 'object' && val !== null) || typeof val === 'function') {if (typeof val.then === 'function') {return true}
    } else {return false}
}
MyPromise.all = function (values) {return new MyPromise((resolve, reject) => {let arr = []
        let index = 0
        let processData = (key, value) => {arr[key] = value
            if (++index === values.length) {resolve(arr)
            }
        }
        for (let i = 0; i < values.length; i++) {let current = values[i]

            if (isPromise(current)) {
                current.then(res => {processData(i, res)
                }, reject)
            } else {processData(i, current)
            }
        }
    })
}

MyPromise.all([1, 2, 3, read('./name.txt'), 3, 4]).then(res => {console.log('all:' + res)
})
// all:1,2,3,'zhufeng',3,4

实现 promise.all() 办法(第二种办法)

/** 
 * promise.all() 全副 能够实现期待所有的异步执行完后  拿到对立的后果
 * 解决异步并发 同步处理结果
 */

let MyPromise = require('./promise_then')

let fs = require('fs')
function read(url) {let dfd = MyPromise.defer()
    fs.readFile(url, 'utf8', function (err, res) {if (err) dfd.reject(err)
        dfd.resolve(res)
    })
    return dfd.promise
}

// read('./name.txt').then(res=>{//     console.log('read:'+res)
// }) 

const isPromise = (val) => {if ((typeof val == 'object' && val !== null) || typeof val === 'function') {if (typeof val.then === 'function') {return true}
    } else {return false}
}
MyPromise.all = function (values) {return new MyPromise((resolve, reject) => {let arr = []
        let index = 0
        let processData = (key, value) => {arr[key] = value
            if (++index === values.length) {resolve(arr)
            }
        }
        for (let i = 0; i < values.length; i++) {let current = values[i]

            if (isPromise(current)) {
                current.then(res => {processData(i, res)
                }, reject)
            } else {processData(i, current)
            }
        }
    })
}

MyPromise.all([1, 2, 3, read('./name.txt'), 3, 4]).then(res => {console.log('all:' + res)
})
退出移动版