手写一个 promise

loong / 89 /

ChatGPT 可用网址,仅供交流学习使用,如对您有所帮助,请收藏并推荐给需要的朋友。
https://ckai.xyz

准备工作

实现一个高阶函数

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

// 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(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,其实就是给函数加一层,不用管函数内部实现
image.png
效果代码:

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)
})

作者
loong
许可协议
CC BY 4.0
发布于
2023-08-27
修改于
2024-12-23
Bonnie image
尚未登录