# 面试复盘(1)-MoreFun魔方文娱

魔方最出名的产品是票星球,平时爱看一些小众宝藏演唱会,所以感觉这产品还是挺活跃的也很想去。

记录一下这次面试里的一些问题,只是部分,并非全部

webAssembly

webAssembly是近年来比较新的前端技术。早在2015年W3C便成立了Wasm社区小组,从2017年开始Wasm相继获得几大浏览器厂商的支持、主流编程语言的支持。

webAssembly的原理

Mozilla开发Emscripten/asm.js 将C++代码编译成js代码时,Google的Chrome团队在试图使用NaCl(Google Native Client)和 PNaCl(Portable NaCl)解决 JavaScript性能问题。Chrome 的解决方案是,Chrome 浏览器可以在沙箱环境中直接执行本地代码。asm.js 和NaCl/PNaC1技术各有优缺点,二者可以取长补短。 Mozilla和Google也看到了这一点,所以从2013年开 始,两个团队就经常交流和合作。直到后来Mozilla和Google决定结合两个项目的长处,合作开发一种基于字节码的技术,WebAssembly就此诞生。

wasm是一种底层汇编语言,能够在PC浏览器和移动浏览器中已接近本地的速度运行。开发者可以使用C/C++/Rust/Go等各种语言进行功能开发,然后通过专用工具emscripten编译到wasm。这个过程完成后就会生成对应的.wasm文件,它能够在浏览器端运行。

webAssembly的使用

WebAssembly可以在Web浏览器中运行。而浏览器主流语言JS也提供了**WebAssembly**对象来支持相关的操作。

加载

由于.wasm是一个文件,所以理所当然地,我们应该先加载这个文件。

ini 复制代码
let sourceWasm = fetch('your-wasm-url.wasm')

fetch是一个异步API,按照常理应该是要等待它的兑现结果再进行下一步操作的。但我们只写到这里,因为WebAssembly对象提供了两种初始化的方式。

初始化

即在浏览器端编译wasm

1.WebAssembly.instantiateStreaming(source)

source:Response 对象或兑现为 Response 对象的 promise。

这允许我们:

javascript 复制代码
const {instance, module} = WebAssembly.instantiateStreaming(sourceWasm)

2.WebAssembly.instantiate(sourceBuffer)

sourceBuffer: 包含你想编译的 Wasm 模块的二进制代码的 类型化数组 或 ArrayBuffer

这就需要:

javascript 复制代码
let sourceBufferWasm = await sourceWasm.arrayBuffer()
const {instance, module} = WebAssembly.instantiate(sourceBufferWasm)

使用

无论通过上述哪种方式来完成初始化都ok,在完成上述工作之后我们只需要通过instance对象就可以使用wasm模块中的功能了:

java 复制代码
instance.exports.add(1, 2); // 假设 wasm 导出了 add 函数
instance.exports.version; // 假设 wasm 导出了 version 变量

胶水文件

通常来说wasm汇编时会生成.wasm文件,.js胶水文件。

csharp 复制代码
import init, { greet } from './pkg/wasm.js'
init().then(wasm => {
    greet('world')
})

这是js中调用wasm的最常见形式,init初始化是个异步操作,初始化完成之后就可以使用相关的函数了。不管是初始化函数、功能函数都来自于胶水代码wasm.js(也可以是别的名字),而胶水代码的核心就是以上的加载、初始化、使用。

小程序与h5的跳转

从小程序跳h5

使用<webview src="{{ src }}">即可

从h5跳小程序

h5只能调用宿主环境(相应小程序平台)的SDK来进行操作

1个h5页面要嵌在不同平台的小程序中使用的问题

javascript 复制代码
function clickFn() {
    if (navigator.userAgent.match(/MicroMessenger/i) && window.wx) {
        // 微信小程序
        window.wx.miniProgram.navigateTo({
            url: `/page/index`,
         });
    } else if (navigator.userAgent.includes('ToutiaoMicroApp')) {
        // 抖音小程序
    } else {
        // 浏览器
    }
}

像这样的代码并不方便管理,使用设计模式优化它:

工厂模式

javascript 复制代码
class clientSDK {
    navigateTo() {
        throw new Error('should implement the method navigateTo')
    }
}
​
class douYinSDK {
    navigateTo(url) {
        wx.miniProgram.navigateTo({url: 'pages/' + url})
    }
}
​
class weiXinSDK {
    navigateTo(url) {
        tt.miniProgram.navigateTo({url: 'pages/' + url})
    }
}
​
class broswerSDK {
    navigateTO(url) {
        // 取决于不同的框架的具体实现
    }
}
​
class SDKFactory {
    getSDKInstance(client) {
        switch (client) {
            case: 'wx':
                return new weiXinSDK();
            case: 'tt':
                return new douYinSDK();
            case: 'broswer':
                return new broswerSDK();
            default:
                throw new Error('Invalid type')
        }
    }
}
javascript 复制代码
// 页面初始化阶段
client = getCurrentClient()
// 方法
function getCurrentClient() {
    let current = 'broswer'
    if (navigator.userAgent.match(/MicroMessenger/i) && window.wx) {
        current = 'wx'
    } else if (navigator.userAgent.includes('ToutiaoMicroApp')) {
        // 抖音小程序
        current = 'tt'
    }
    const factory = new SDKFactory()
    return factory.getSDKInstance(current)
}
​
function clickFn() {
    client.navigateTo('index')
}

策略模式

javascript 复制代码
class routeStrategy {
    constructor(strategy) {
        this.strategy = strategy
    }
    
    setStrategy(strategy) {
        this.strategy = strategy
    }
    
    executeStrategy(...args) {
        return this.strategy(...args)
    }
}
javascript 复制代码
// 页面初始化阶段
const currentRouter = new routeStrategy()
getCurrentClient(currentRouter)
​
// 方法
function getCurrentClient(strategy) {
    let current = 'broswer'
    if (navigator.userAgent.match(/MicroMessenger/i) && window.wx) {
        strategy.setStrategy(wx.miniProgram.navigateTo)
    } else if (navigator.userAgent.includes('ToutiaoMicroApp')) {
        strategy.setStrategy(tt.miniProgram.navigateTo)
    } else {
        // 浏览器端要看框架
    }
}
​
function clickFn() {
    currentRouter.executeStrategy('pages/index')
}

还是太紧张了,当时太支支吾吾了

算法题

依赖收集

文件入口:A,

依赖项:[['A', 'B'], ['B', 'C'], ['B', 'D'], ['E', 'F'], ['C', 'E'], ['F', 'D'], ['G', 'H']]

根据依赖项,收集所有相关依赖

ini 复制代码
function collectDeps (index, deps) {
    let map = new Map()
    deps.forEach(arr => {
        const key = arr[0]
        if (map.has(key)) {
            map.get(key).push(arr[1])
        } else {
            map.set(key, [arr[1]])
        }
    })
    let res = map.get(index)
    res.push(index)
    for (let i = 0; i < res.length; i++) {
        const item = res[i];
        if (map.has(item)) {
            res = res.concat(map.get(item))
            map.delete(item)
        }
    }
    return new Set(res)
}
​
console.log(collectDeps(index, deps));

要点:

  • Map的使用
  • Set去重
  • 使用for()循环而不是forEach,因为forEach只会根据初始的数组状态来遍历,for()可以处理更新的数组

当时脑一抽忘了concat返回新数组了......

总结

  • 有些场景没有遇到过,但是总是会有类似的,不用慌,思考一下总会有头绪
  • 对webassembly的内容梳理了一下,毕竟这算是过往工作中的小亮点
  • 设计模式
  • 太容易紧张了,一紧张就犯错

没发挥好啊啊啊啊,还挺喜欢他们家产品的其实。

相关推荐
恋猫de小郭3 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅10 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606110 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了10 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅10 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅11 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅11 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment11 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅12 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端