Git Product home page Git Product logo

ying-study's Introduction

  • 👋 你好,我是陈大鱼头
  • 👀 我是一枚前端工程师
  • 💌 我的微信公众号是:鱼头的Web海洋(好久没更新了)
  • 🏡 我的技术博客:https://blog.krissarea.com/
  • 💬 微信号:krisChans95
  • 📧 邮箱:[email protected]

ying-study's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ying-study's Issues

7. 一道对象面试题

给定一个 “扁平化” 字典对象,其键以点分隔。

例如:

{
  'A': 1,
  'B.B': 3,
  'CC.D.E': 4,
  'CC.D.F': 5
}

实现将其转换为 “”嵌套“” 字典对象的功能。

在上述情况下,嵌套版本如下:

{
  'A': 1,
  'B' {
    'A': 2,
    'B': 3
  }
  'CC' {
    'D': {
        'E': 4,
        'F': 5
     }
  }
}

确保字典中任何的键都不是其他键的前缀。

6. 一道数组面试题

给定一个整数数组 [6, 4, -3, 5, -2, -1, 0, 1, -9] ,实现一个函数,将所有正数向左一定,并将所有负数向右移动。
尽力将其时间复杂度设为O(n),并将空间复杂度设为O(1)。

4. 一道数组转对象的面试题

[
    ["a", "aa", "aaa", "aaaa"],
    ["b", "bb", "bbb"],
    ["a", "ab", "aba"],
    ["a", "aa", "aab"]
] 转为:
[
    {
        "name" : "a",
        "child" : [
            {
                "name" : "aa",
                "child" : [
                    {
                        "name" : "aaa",
                        "child" : [
                            {
                                "name" : "aaaa",
                                "child" : []
                            }
                        ]
                    },
                    {
                        "name" : "aab",
                        "child" : []
                    }
                ]

            },
            {
                "name" : "ab",
                "child" : [
                    {
                        "name": "aba",
                        "child" : []
                    }
                ]

            }
        ]
    },
    {
        "name": "b",
        "child" : [
            {
                "name" : "bb",
                "child" : [
                    {
                        "name" : "bbb",
                        "child" : []
                    }
                ]
            }
        ]
    }

]

17. 图片压缩题

需要对上传的图片进行压缩,要求图片总像素不大于 400(20 20),
假如输入一张 30
80 的图片,问长边应该压缩到多少,如何计算?

15. 对象赋值,将一个对象中有指定键名的值赋值给另一个对象中相同的键中

'use strict'
// 编写一段函数,将一个对象某一个层级中与指定键相同的键值赋值到第二个对象某一层级中有相同键的值。
// 例如:
// input
const tree1 = {
    aa: {
        bb: {
            cc: '123'
        }
    }
}
const tree2 = {
    0: {
        id: 0,
        aa: {
            oo: 89,
            bb: {
                cc: null
            }
        }
    },
    1: {
        id: 1,
        aa: {
            oo: 84,
            bb: {
                cc: null
            }
        }
    }
}
const key = 'cc'

// output
const tree2 = {
    0: {
        id: 0,
        aa: {
            oo: 89,
            bb: {
                cc: '123'
            }
        }
    },
    1: {
        id: 1,
        aa: {
            oo: 84,
            bb: {
                cc: '123'
            }
        }
    }
}

1. 什么是时间分片(Time Slicing)?

什么是时间分片(Time Slicing)?

根据W3C性能小组的介绍,超过50ms的任务就是长任务。

1-1

图片来自使用 RAIL 模型评估性能

根据上图我们可以知道,当延迟超过100ms,用户就会察觉到轻微的延迟。

所以为了避免这种情况,我们可以使用两种方案,一种是Web Worker,另一种是时间切片(Time Slicing)

Web Worker

我们都知道,JS是单线程,所以当我们在运行长任务时,容易造成页面假死的状态,虽然我们可以将任务放在任务队列中,通过异步的方式执行,但这并不能改变JS的本质。

所以为了改变这种现状,whatwg推出了Web Workers

具体的语法不会进行说明,有兴趣的童鞋可以查看MDN Web Worker

我们可以看看使用了Web Worker之后的优化效果:

const testWorker = new Worker('./worker.js')
setTimeout(_ => {
  testWorker.postMessage({})
  testWorker.onmessage = function (ev) {
    console.log(ev.data)
  }
}, 5000)

// worker.js
self.onmessage = function () {
  const start = performance.now()
  while (performance.now() - start < 1000) {}
  postMessage('done!')
}

1-2

代码以及截图来自于让你的网页更丝滑

时间切片(Time Slicing)

时间切片是一项使用得比较广的技术方案,它的本质就是将长任务分割为一个个执行时间很短的任务,然后再一个个地执行。

这个概念在我们日常的性能优化上是非常有用的。

例如当我们需要在页面中一次性插入一个长列表时(当然,通常这种情况,我们会使用分页去做)。

如果利用时间分片的概念来实现这个功能,我们可以使用requestAnimationFrame+DocumentFragment

关于这两个API,我同样不会做详细的介绍,有兴趣的可以查看MDN requestAnimationFrameMDN DocumentFragment

这里有两个DEMO,大家可以对比下流畅程度:

未使用时间分片:

<style>
    * {
        margin: 0;
        padding: 0;
    }
    .list {
        width: 60vw;
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
    }
</style>
<ul class="list"></ul>
<script>
    'use strict'
    let list = document.querySelector('.list')
    let total = 100000
    for (let i = 0; i < total; ++i) {
        let item = document.createElement('li')
        item.innerText = `我是${i}`
        list.appendChild(item)
    }
</script>

使用时间分片:

<style>
    * {
        margin: 0;
        padding: 0;
    }
    .list {
        width: 60vw;
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
    }
</style>
<ul class="list"></ul>
<script>
    'use strict'
    let list = document.querySelector('.list')
    let total = 100000
    let size = 20
    let index = 0
    const render = (total, index) => {
        if (total <= 0) {
            return
        }
        let curPage = Math.min(total, size)
        window.requestAnimationFrame(() => {
            let fragment = document.createDocumentFragment()
            for (let i = 0; i < curPage; ++i) {
                let item = document.createElement('li')
                item.innerText = `我是${index + i}`
                fragment.appendChild(item)
            }
            list.appendChild(fragment)
            render(total - curPage, index + curPage)
        })
    }
    render(total, index)
</script>

没有做太多的测评,但是从用户视觉上的感受来看就是,第一种方案,我就是想刷新都要打好几个转,往下滑的时候也有白屏的现象。

除了上述的生成DOM的方案,我们同样可以利用Web Api requestIdleCallback 以及ES6 API Generator]来实现。

同样不会做太多的介绍,详细规则可以看MDN requestIdleCallback以及MDN Generator

具体实现如下:

<style>
    * {
        margin: 0;
        padding: 0;
    }
    .list {
        width: 60vw;
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
    }
</style>
<ul class="list"></ul>
<script>
    'use strict'
    function gen(task) {
      requestIdleCallback(deadline => {
        let next = task.next()
        while (!next.done) {
          if (deadline.timeRemaining() <= 0) {
            gen(task)
            return
          }
          next = task.next()
        }
      })
    }
    let list = document.querySelector('.list')
    let total = 100000
    function* loop() {
      for (let i = 0; i < total; ++i) {
        let item = document.createElement('li')
        item.innerText = `我是${i}`
        list.appendChild(item)
        yield
      }
    }
    gen(loop())
</script>

参考资料

  1. web-performance
  2. Measure Performance with the RAIL Model
  3. 让你的网页更丝滑
  4. 「前端进阶」高性能渲染十万条数据(时间分片)

10. 一道异步相关的面试题

实现一个Person类,类里有eat、work、sleep三个方法,支持如下调用方式eat().work(10).sleep(5)

打印结果为
eat()
eat()->work(10) //等待10后打印
eat()->work(10)->sleep(5) //等待5秒后打印

[WIP]: 整理的手写面经题

  1. 实现防抖和节流函数
  2. 实现深拷贝
  3. 实现继承(包括原型继承、构造函数继承、组合继承、寄生式继承、寄生组合式继承等多种方式)
  4. 实现一个 Promise
  5. 实现一个发布-订阅模式
  6. 实现一个观察者模式
  7. 实现一个数组扁平化函数
  8. 实现一个数组去重函数
  9. 实现一个简单的模板引擎
  10. 实现一个简单的事件委托函数
  11. 实现call、apply、bind函数
  12. 实现事件监听函数
  13. 实现原生ajax函数
  14. 实现new操作符

2. JavaScript实现指定数量的并发限制

在网上看到这么一道题:

2-1

这道题跟鱼头这篇记录『什么是时间分片(Time Slicing)?』有点相似,但不同的是这次是限制异步并发的数量。

所以话不多说,我们先来康康实现

首先我们来实现一个分割数组的函数~

const group = (list = [], max = 0) => {
    if (!list.length) {
        return list
    }
    let results = []
    for (let i = 0, len = list.length; i < len; i += max) {
        results.push(list.slice(i, i + max))
    }
    return results
}

这里就是根据指定的并发数量来分割数组。主要就是for + slice,这没啥好说的

接下来我们再来一个用async + await实现的请求集合封装。

我们通Promise.allSettled去执行每一组的请求集合。

Promise.allSettled是一个新的API,跟Promise.all差不多的用法,也是接受的数组,不过不同的是Promise.allSettled会等所有任务结束之后才会返回结果,而Promise.all只要有一个reject就会返回结果。

const requestHandler = async (
    groupedUrl = [],
    callback = () => { }
) => {
    if (!groupedUrl.length) {
        callback()
        return groupedUrl
    }
    const newGroupedUrl = groupedUrl.map(fn => fn())
    const resultsMapper = (results) => results.map(callback)
    const data = await Promise.allSettled(newGroupedUrl).then(resultsMapper)
    return data;
}

接下来就是主函数

const sendRequest = async (
    urls = [],
    max = 0,
    callback = () => { }
) => {
    if (!urls.length) {
        return urls
    }
    const groupedUrls = group(urls, max)
    const results = []
    console.log('start !')
    for (let groupedUrl of groupedUrls) {
        try {
            const result = await requestHandler(groupedUrl, callback)
            results.push(result)
            console.log('go')
        } catch { }
    }
    console.log('done !')
    return results
}

这里就是利用了for + async + await来限制并发。等每次并发任务结果出来之后再执行下一次的任务。

我们执行下栗子:

const p1 = () => new Promise((resolve, reject) => setTimeout(reject, 1000, 'p1'))
const p2 = () => Promise.resolve(2)
const p3 = () => new Promise((resolve, reject) => setTimeout(resolve, 2000, 'p3'))
const p4 = () => Promise.resolve(4)
const p5 = () => new Promise((resolve, reject) => setTimeout(reject, 2000, 'p5'))
const p6 = () => Promise.resolve(6)
const p7 = () => new Promise((resolve, reject) => setTimeout(resolve, 1000, 'p7'))
const p8 = () => Promise.resolve(8)
const p9 = () => new Promise((resolve, reject) => setTimeout(reject, 1000, 'p9'))
const p10 = () => Promise.resolve(10)
const p11 = () => new Promise((resolve, reject) => setTimeout(resolve, 2000, 'p10'))
const p12 = () => Promise.resolve(12)
const p13 = () => new Promise((resolve, reject) => setTimeout(reject, 1000, 'p11'))
const p14 = () => Promise.resolve(14)

const ps = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14]
sendRequest(ps, 3, ({reason, value}) => {
    console.log(reason || value)
})

2-2

OK,我们看到结果是如我们所愿的

3. 一道排列组合的面试题

问题如下:

let input = [
    { id: '17', caption: '颜色', types: ['黑', '棕'] },
    { id: '23', caption: '材质', types: ['牛皮'] },
    { id: '24', caption: '尺码', types: ['40', '41', '42'] }
]

let output = [
    { "17": "黑", "23": "牛皮", "24": "40" },
    { "17": "黑", "23": "牛皮", "24": "41" },
    { "17": "黑", "23": "牛皮", "24": "42" },
    { "17": "棕", "23": "牛皮", "24": "40" },
    { "17": "棕", "23": "牛皮", "24": "41" },
    { "17": "棕", "23": "牛皮", "24": "42" }
]

一道排列组合题,也挺有意思的,有兴趣的可以来回答一波

[WIP]: 常见的 JS / TS 手写题

  • 实现防抖和节流函数
  • 实现深拷贝
  • 实现继承(包括原型继承、构造函数继承、组合继承、寄生式继承、寄生组合式继承等多种方式)
  • 实现一个 Promise
  • 实现一个观察者模式
  • 实现一个数组扁平化函数
  • 实现一个数组去重函数
  • 实现一个简单的模板引擎
  • 实现一个简单的事件委托函数
  • 实现 call、apply、bind 函数
  • 实现事件监听函数
  • 实现原生 ajax 函数
  • 实现 new 操作符
  • 实现 instanceof 方法

14. A、 B 、 C 是 3 个字符串。把 A 中包含的所有 B 都替换为 C ,如果替换以后还有 B 就继续替 换,直到 A 不包含 B 为止。

A、 B 、 C 是 3 个字符串。把 A 中包含的所有 B 都替换为 C ,如果替换以后还有 B 就继续替 换,直到 A 不包含 B 为止。

  1. 请编写程序实现以上功能。不允许使用系统提供的字符串比较、查找和替换函数。
  2. 以上程序是否总是能正常输出结果?如果不是,列出哪些情况下无法正常输出结果,尽 可能详细和全面

12. 求数组上的交集

例:
[2, 6]、[1, 4]、[5, 8]
交集为:
[2, 4]、[5, 6]

注:
第一个解的意思是 [2, 6]、[1, 4]的区间为[2, 4]
第二个解的意思是 [2, 6]、[5, 8]的区间为[5, 6]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.