# 面试复盘(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的内容梳理了一下,毕竟这算是过往工作中的小亮点
  • 设计模式
  • 太容易紧张了,一紧张就犯错

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

相关推荐
蓝胖子的小叮当5 分钟前
JavaScript基础(十四)字符串方法总结
前端·javascript
跟橙姐学代码33 分钟前
Python 函数实战手册:学会这招,代码能省一半!
前端·python·ipython
森之鸟38 分钟前
审核问题——鸿蒙审核返回安装失败,可以尝试云调试
服务器·前端·数据库
jiayi1 小时前
从 0 到 1 带你打造一个工业级 TypeScript 状态机
前端·设计模式·状态机
轻语呢喃1 小时前
CSS水平垂直居中的9种方法:原理、优缺点与差异对比
前端·css
!win !1 小时前
uni-app支付宝端彻底禁掉下拉刷新效果
前端·小程序·uni-app
xw51 小时前
uni-app支付宝端彻底禁掉下拉刷新效果
前端·支付宝
@大迁世界1 小时前
这次 CSS 更新彻底改变了我的 CSS 开发方式。
前端·css
IT_陈寒2 小时前
Python 3.12 新特性实战:5个让你的代码效率提升50%的技巧!🔥
前端·人工智能·后端
Apifox2 小时前
Apifox 8 月更新|新增测试用例、支持自定义请求示例代码、提升导入/导出 OpenAPI/Swagger 数据的兼容性
前端·后端·测试