每日前端手写题--day17

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

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

  1. 实现图片懒加载

  2. 实现生成器的执行器函数

  3. 判断一个函数是不是生成器

下面是我的一些理解:

1. 实现图片懒加载

1.1 使用getBoundingClientRect实现

实现思路:

  1. 利用闭包保存三个变量imgs、len; 分别表示: 待加载的图片数组;多有图片的数目。

  2. 闭包返回一个函数,这个函数的作用为:遍历imgs,找到满足加载条件的图片进行加载然后从待加载的数组中移除出去。

  3. 如果某次lazyLoad执行完毕之后发现待加载的图片数组为空,表示所有的图片都已经加载完毕了,从此再也不需要执行lazyLoad函数了,这个时候就将lazyLoad的触发条件关闭

  4. 设置scroll事件触发的时候执行lazyLoad函数

const lazyLoad = (
    function () {
        let imgs = [...document.querySelectorAll("img")];
        const len = imgs.length;

        return function () {
            imgs = imgs.filter(img=>{
                const rect = img.getBoundingClientRect();
                if(rect.top >= window.innerHeight) return true;
                img.src = img.dataset.src;
                return false;
            });

            if (len === imgs.length)  document.removeEventListener('scroll', lazyLoad);
        }
    }
)();

document.addEventListener('scroll', lazyLoad);

1.2 使用IntersectionObserver实现

实现思路:

  1. 使用IntersectionObserver观察器对每一个img标签进行监控

  2. 观察器的回调中会通过判断img的intersectionRatio属性判断出此img是否需要加载

  3. 如果需要加载就在加载之后取消监控

const lazyLoad = function () {
    const imgs = [...document.querySelectorAll("img")];

    const observer = new IntersectionObserver(
        entries => void entries.forEach(
            entry => {
                if (entry.intersectionRatio > 0) {
                    const _img = entry.target;
                    _img.src = _img.dataset.src;
                    observer.unobserve(_img);
                }
            }
        )
    );

    imgs.forEach(img => observer.observe(img));
}

2. 实现生成器的执行器函数

这个稍微有些复杂,如果想要彻底掌握一定要在坐地铁的时候多想几遍,本质上并不难,但是平时使用异步函数的机会相对较少,所以有点绕。

写一个函数执行下面的这个生成器,对执行过程不断的进行优化,进而提取出执行生成器的样本函数co

2.0 等待被执行的生成器

function* gFunc () {
    let _rst  = 0;
    _rst = yield Promise.resolve(_rst);
    console.log('_rst1',_rst);
    _rst = yield Promise.resolve(_rst+1);
    console.log('_rst2',_rst);
    _rst = yield Promise.resolve(_rst+1);
    console.log('_rst3',_rst);
}

2.1 使用同步代码暴力执行

const lowCo = (gFunc) => {
    let value;
    let done;
    const it = gFunc();

    ({ value, done } = it.next());
    if(done) return value;
    value.then(d=>{
        ({ value, done } = it.next(d));
        if(done) return value;
        value.then(d=>{
            ({ value, done } = it.next(d));
            if(done) return value;
            value.then(d=>{
                ({ value, done } = it.next(d));
            })
        })
    })
}


lowCo(gFunc);

 * _rst1 0
 * _rst2 1
 * _rst3 2
 */

2.2 观察代码,发现大量的重复代码,对其进行分层

const lowCo2 = (gFunc) => {
    let value;
    let done;
    const it = gFunc();

    
    ({ value, done } = it.next());
    if(done) return value;
    value.then(d=>{
        
        ({ value, done } = it.next(d));
        if(done) return value;
        value.then(d=>{
            
            ({ value, done } = it.next(d));
            if(done) return value;
            value.then(d=>{
                ({ value, done } = it.next(d));
            })
        })
    })
}

2.3 使用递归的方式消除重复代码

const lowCo3 = (gFunc) => {
    let value;
    let done;
    const it = gFunc();

    const tick = _ => {
        ({ value, done } = _);
        if(done) return value;
        value.then(d=>{
            tick(it.next(d))
        });
    }
    return tick(it.next());
}

2.4 使用Promise.resolve增加容错

const lowCo4 = (gFunc) => {
    let value;
    let done;
    const it = gFunc();

    const tick = _ => {
        ({ value, done } = _);
        if(done) return value;
        Promise.resolve(value).then(d=>{
            tick(it.next(d))
        });
    }
    return tick(it.next());
}

2.5 将结果promisify

const lowCo5 = (gFunc) => {
    let value;
    let done;
    const it = gFunc();

    return new Promise((res,rej)=>{
        const tick = _ => {
            ({ value, done } = _);
            if(done) return res(value);
            Promise.resolve(value).then(d=>{
                tick(it.next(d))
            }).catch(e=>rej(e));
        }
        tick(it.next());
    })
}

2.6 感受自由

const co = gFunc => (it = gFunc(),new Promise((res,rej)=>(tick = _ => _.done ? res(_.value): Promise.resolve(_.value).then(d=>tick(it.next(d))).catch(e=>rej(e)),tick(it.next()))));

3. 判断一个函数是不是生成器

先判断是不是函数,再判断其构造函数的名称

const testGenerator = f => typeof f === "function" && f.constructor?.name === "GeneratorFunction";

最后

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

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Web面试那些事儿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值