每日前端手写题--day16

本文介绍了如何将传入的函数Promise化,实现fs.readFile的异步版本,探讨了promisify原理,以及使用代理、闭包和WeakMap实现对象私有化的方法。同时,文章提及了封装异步函数以避免await错误溢出的最佳实践。
摘要由CSDN通过智能技术生成

如果你最近想要换工作或者巩固一下自己的前端知识基础,不妨和我一起参与到每日刷题的过程中来,如何?

第16天要刷的手写题如下:

  1. 实现一个函数,能够将传入的函数promisify

  2. 多种方式实现对象私有化属性

  3. 封装异步函数以防止await操作符作用的时候其出错溢出

下面是我的一些理解:

1. 实现一个函数,能够将传入的函数promise化

原理:将输入的函数A映射称为函数B, B函数的返回值是一个Promise对象,在此Promise对象内部的同步代码中会执行原来的函数A并为其构造一个临时的回调函数,在此临时回调函数内部改变包裹的Promise对象的状态,从而实现数据的传递。

下面就以fs.readFile演化成fs.readFileSync为例解释上面的原理:

1.1 fs.readFile的使用

fs.readFile('data.json', 'utf8', function(err, data){
    if (err) {
        handleError(err);
    } else {
        handleData(data);
    }
});

!上述代码中的handleErrorhandleData是外部提供的将错误/数据传递出去的接口。

1.2 使用一个函数包裹这个过程,将其中使用到的量参数化

const _f = (...args) => {
    fs.readFile(...args, function(err, data){
        if (err) {
            handleError(err);
        } else {
            handleData(data);
        }
    });
}

_f('data.json', 'utf8');

1.3 使用柯里化的思想将fs.readFile也作为参数

const _c = (exec) => {
    return (...args) => {
        exec(...args, function(err, data){
            if (err) {
                handleError(err);
            } else {
                handleData(data);
            }
        });
    }
}

_c(fs.readFile)('data.json', 'utf8');


1.4 使用Promise的resolve和reject作为handleError和handleData

const _c = (exec) => {
    return new Promise ((handleData, handleError)=>{
        (...args) => {
            exec(...args, function(err, data){
                if (err) {
                    handleError(err);
                } else {
                    handleData(data);
                }
            });
        }
    })
}

const _p = _c(fs.readFile)('data.json', 'utf8');

1.5 使用void、箭头函数和三目运算对上面的函数进行简化

const _c = exec => new Promise ((handleData, handleError)=>void (...args) => void exec(...args, (err, data) => void err ? handleError(err) : handleData(data)));

最后的答案就是:exec => new Promise ((handleData, handleError)=>void (...args) => void exec(...args, (err, data) => void err ? handleError(err) : handleData(data)));

如果想要继续装一下,写成e => new Promise((s, j)=> (...a) => e(...a, (r, d) => r ? j(r) : s(d)))

1.6 总结

所谓promisify,其本质就是使用promise两种修改状态的函数作为处理失败和成功的函数。

2. 使用多种方式实现对象私有化属性

常见的实现方法有三种:

  • 使用代理,即Proxy

  • 使用闭包和Symbol

  • 使用闭包和哈希表

2.1 使用代理,对带有特殊标记的属性做特殊的处理

需要劫持的是get和ownKeys两种操作:

const getProxyObj = obj => new Proxy ( obj, {
    get (target, key) {
        if(key.startsWith('_')) throw new Error();
        return Reflect.get(target, key);
    },
    ownKeys (target) {
        return Reflect.ownKeys(target).filter(v=>!v.startsWith('_'));
    }
}) 

2.2 使用闭包提供一个独一无二的属性名

由于在闭包的外部拿不到这个独一无二的属性名,也无法将其生产出来,所以可以在一定程度上保证私有性;但是如果使用键的遍历方法还是可以找到的。

const MC = (
    function () {
        const _age = Symbol('age');
        return class MC {
            constructor(name){
                this._name = name;
            }
        }
    }
)();

2.3 使用闭包提供一个哈希表,哈希表中存放的是实例和实例的私有属性的对应关系

  • 在闭包外面拿不到这个哈希表所以可以在一定程度上保证私有性;

  • 使用WeakMap而不是Map解决内存泄漏的问题

const MC = (
    function () {
        const _wm = new WeakMap();
        return class MC {
            constructor(name, age){
                _wm.set(this, {name, age});
            }
            get(key){
                return _wm.get(this)[key];
            }
        }
    }
)();

此外还可以在编译阶段解决此问题,比如使用ts中的private修饰符。

3. 封装异步函数以防止await操作符作用的时候其出错溢出

原理:将异步函数A通过此函数映射成为异步函数B,在B中执行A,同时对错误进行捕获并输出

const useWrapper = async originFunc => {
    try {
        const rst = await originFunc();
        return [rst, null];
    } catch (err) {
        return [null, err];
    }
};



let data;
try {
    data = await originFunc();
} catch (e) {
    data = null;
}


const [data, err] =  await useWrapper(originFunc);

最后

如果你现在正在找工作,可以私信“web”进群领取前端面试小册以及更多阿里、字节大厂面试真题合集,和p8大佬一起交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Web面试那些事儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值