无名小贝勒

无名小贝勒 查看完整档案

杭州编辑天津大学  |  通信工程 编辑阿里巴巴  |  前端开发 编辑 segmentfault.com/u/onemonth 编辑
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

无名小贝勒 评论了文章 · 2019-04-09

阿里、网易、滴滴共十次前端面试碰到的问题

前一段时间一直在不断地面试,无奈个人技术能力有限、项目经验缺乏,最终都没有进入到HR面试环节,全~~挂~~了~~

面试了这么多,结果不是太好,有点儿受打击,也促使我近期静下心来反思自己的问题:哪些技术知识掌握的还不错,哪些还有待提高,哪些是需要去恶补的。

阿里面试了三个部门,都是在二面挂的,网易和滴滴也是各两轮技术面试,加一起就是十次面试经历。在此回忆总结一下,既是给社区朋友的一个参考,反馈社区,更是给自己一个好好的总结。

HTML

  • HTML5新增了哪些内容或API,使用过哪些

  • input和textarea的区别

  • 用一个div模拟textarea的实现

  • 移动设备忽略将页面中的数字识别为电话号码的方法 --- 2017.06.10补充

CSS

  • 左右布局:左边定宽、右边自适应,不少于3种方法

  • CSS3用过哪些新特性

  • BFC、IFC

  • 对栅格的理解

  • (水平)居中有哪些实现方式

  • 1像素边框问题

JavaScript

  • 图片懒加载

  • 实现页面加载进度条

  • 事件委托

  • 实现extend函数

  • 为什么会有跨域的问题以及解决方式

  • jsonp原理、postMessage原理

  • 实现拖拽功能,比如把5个兄弟节点中的最后一个节点拖拽到节点1和节点2之间

  • 动画:setTimeout何时执行,requestAnimationFrame的优点

  • 手写parseInt的实现:要求简单一些,把字符串型的数字转化为真正的数字即可,但不能使用JS原生的字符串转数字的API,比如Number()

  • 编写分页器组件的时候,为了减少服务端查询次数,点击“下一页”怎样能确保还有数据可以加载(请求数据不会为空)?

  • ES6新增了哪些特性,使用过哪些,也有当场看代码说输出结果的

  • JS模块化的实践

  • require.js的实现原理(如果使用过webpack,进一步会问,两者打包的异同及优缺点)

  • promise的实现原理,进一步会问async、await是否使用过

  • 实现gulp的功能

  • 使用前端框架(angular/vue/react)带来哪些好处,相对于使用jQuery

  • vue双向数据绑定的实现

  • 单页应用,如何实现其路由功能

性能优化

  • 项目中使用过哪些优化方法

  • 输入一个URL,Enter之后发生了什么

  • (承上)页面的渲染过程

  • 优化中会提到缓存的问题,问:静态资源或者接口等如何做缓存优化

  • 页面DOM节点太多,会出现什么问题?如何优化?

项目经历

这些大公司招聘都是高级工程师起步,所以对简历上的项目会刨根问底。很多很多问题都是由项目中拓展开的,像优化相关的东西,还有前面提到的require.js、promise、gulp,项目中用到了某项技术,高级工程师的要求是:不仅会用,更要知道其原理。对自己的提醒:项目中用到的技术,不能说完全掌握其原理吧,但大致的实现还是有必要了解一下的。

  • 介绍一下你做的这个项目,进一步细问:整个项目有哪些模块,你主要负责哪些

  • 你在项目中的角色

  • 你在项目中做的最出彩的一个地方

  • 碰到过什么样的困难,怎么解决的

  • (如果你是这个项目的负责人),任务怎么分配的,有没有关注过团队成员的成长问题

  • 前端安全问题:CSRF和XSS

其他

  • 为什么选择做前端(我靠,我都快转前端两年了,还在问这个问题啊...)

  • 你希望进入一个什么样的团队

  • 你有什么问题想问我(面试官)的吗?


前前后后有两个月时间,暂时只回忆起这么多了,如果还有其他的,后期我会补上。

webpack其实也是必问的,由于我说还没使用过webpack,只是了解,写过demo,面试官就没问太深。如果你的简历中有提到webpack,请提前准备好,比如webpack打包原理、如何写webpack插件等。

面试阿里云那个岗位的时候,有要求算法和数据结构,有能力者多多准备吧。

阿里、网易的面试几乎都是围绕项目展开的,所以提醒自己搬砖的时候多想想、多看看,多站在一个高度去看整个项目:用到什么技术,技术实现原理是什么,项目框架怎么搭建的,采取安全措施了吗...


后记

有几个岗位感觉就是挂在了项目上。自己做过一个前后端分离项目,但是经过几次面试,发现这个项目还存在某些问题,比如:整个登录注册系统是不完善的,关于权限的处理上甚至是有很大缺陷的;这个项目的node层只是起到构建前端项目(gulp)、渲染index.ejs、代理转发api接口等作用,但是面试官指出说你这个node也太简单了,导致我都在怀疑这是个假的前后端分离...还是需要大神带多见见世面啊,求带...

虽然五次面试都没成功,但自己也收获了很多很多:认识了大牛hb,一个超有文艺气息的资深前端;多谢fw大大帮我内推阿里,十分感谢您对我的认可;也见到了平时只能在视频上看到的cjf老师,谢谢您的指点;对高级前端工程师所具备的技能有了更清晰的认识;肯定也增加了很多面试经验...

再好好提升一下,打算过段时间重新上阵,也祝自己多点好运气,早日进入心仪的企业,毕竟,当初来杭州的时候就是以网易、阿里为目标的。

查看原文

无名小贝勒 收藏了文章 · 2019-03-05

聊一聊 cookie

咱们不搞一开始就一大堆理论知识介绍,怕把人讲懵了...... 咱们换一个思维方式——"从现象看本质",先说说我们看到了什么,再从看到的现象中提出问题,最后深入寻找答案。

我们看到的 cookie

我自己创建了一个网站,网址为http://ppsc.sankuai.com。在这个网页中我设置了几个cookieJSSESSIONIDPA_VTIMEskmtutctest

在 chrome 浏览器中打开这个网站,进入开发者模式,点击Resources栏 -> 选择cookies,我们会看到如下图所示的界面:

图片描述

解释一下:左边栏Cookies下方会列举当前网页中设置过cookie的域都有哪些。上图中只有一个域,即“ppsc.sankuai.com”。而右侧区域显示的就是某个域下具体的 cookie 列表,对应上图就是“ppsc.sankuai.com”域下设置的4个cookie

在这个网页中我往http://ppsc.sankuai.com/getList接口发了一个 Ajax 请求,request header如下图所示:

图片描述

从上图中我们会看到request header中自动添加了Cookie字段(我并没有手动添加这个字段哦~),Cookie字段的值其实就是我设置的那4个 cookie。这个请求最终会发送到http://ppsc.sankuai.com这个服务器上,这个服务器就能从接收到的request header中提取那4个cookie

上面两张图展示了cookie的基本通信流程:设置cookie => cookie被自动添加到request header中 => 服务端接收到cookie。这个流程中有几个问题需要好好研究:

  1. 什么样的数据适合放在cookie中?

  2. cookie是怎么设置的?

  3. cookie为什么会自动加到request header中?

  4. cookie怎么增删查改?

我们要带着这几个问题继续往下阅读。

cookie 是怎么工作的?

首先必须明确一点,存储cookie是浏览器提供的功能。cookie 其实是存储在浏览器中的纯文本,浏览器的安装目录下会专门有一个 cookie 文件夹来存放各个域下设置的cookie

当网页要发http请求时,浏览器会先检查是否有相应的cookie,有则自动添加在request header中的cookie字段中。这些是浏览器自动帮我们做的,而且每一次http请求浏览器都会自动帮我们做。这个特点很重要,因为这关系到“什么样的数据适合存储在cookie中”。

存储在cookie中的数据,每次都会被浏览器自动放在http请求中,如果这些数据并不是每个请求都需要发给服务端的数据,浏览器这设置自动处理无疑增加了网络开销;但如果这些数据是每个请求都需要发给服务端的数据(比如身份认证信息),浏览器这设置自动处理就大大免去了重复添加操作。所以对于那设置“每次请求都要携带的信息(最典型的就是身份认证信息)”就特别适合放在cookie中,其他类型的数据就不适合了。

但在 localStorage 出现之前,cookie被滥用当做了存储工具。什么数据都放在cookie中,即使这些数据只在页面中使用而不需要随请求传送到服务端。当然cookie标准还是做了一些限制的:每个域名下的cookie 的大小最大为4KB,每个域名下的cookie数量最多为20个(但很多浏览器厂商在具体实现时支持大于20个)。

cookie 的格式

document.cookie

JS 原生的 API提供了获取cookie的方法:document.cookie(注意,这个方法只能获取非 HttpOnly 类型的cookie)。在 console 中执行这段代码可以看到结果如下图:

图片描述

打印出的结果是一个字符串类型,因为cookie本身就是存储在浏览器中的字符串。但这个字符串是有格式的,由键值对 key=value构成,键值对之间由一个分号和一个空格隔开。

cookie 的属性选项

每个cookie都有一定的属性,如什么时候失效,要发送到哪个域名,哪个路径等等。这些属性是通过cookie选项来设置的,cookie选项包括:expiresdomainpathsecureHttpOnly。在设置任一个cookie时都可以设置相关的这些属性,当然也可以不设置,这时会使用这些属性的默认值。在设置这些属性时,属性之间由一个分号和一个空格隔开。代码示例如下:

"key=name; expires=Thu, 25 Feb 2016 04:18:00 GMT; domain=ppsc.sankuai.com; path=/; secure; HttpOnly"

expires

expires选项用来设置“cookie 什么时间内有效”。expires其实是cookie失效日期,expires必须是 GMT 格式的时间(可以通过 new Date().toGMTString()或者 new Date().toUTCString() 来获得)。

expires=Thu, 25 Feb 2016 04:18:00 GMT表示cookie讲在2016年2月25日4:18分之后失效,对于失效的cookie浏览器会清空。如果没有设置该选项,则默认有效期为session,即会话cookie。这种cookie在浏览器关闭后就没有了。

expires 是 http/1.0协议中的选项,在新的http/1.1协议中expires已经由 max-age 选项代替,两者的作用都是限制cookie 的有效时间。expires的值是一个时间点(cookie失效时刻= expires),而max-age 的值是一个以为单位时间段(cookie失效时刻= 创建时刻+ max-age)。
另外,max-age 的默认值是 -1(即有效期为 session );若max-age有三种可能值:负数、0、正数。负数:有效期session0:删除cookie;正数:有效期为创建时刻+ max-age

domain 和 path

domain是域名,path是路径,两者加起来就构成了 URL,domainpath一起来限制 cookie 能被哪些 URL 访问。

一句话概括:某cookie的 domain为“baidu.com”, path为“/ ”,若请求的URL(URL 可以是js/html/img/css资源请求,但不包括 XHR 请求)的域名是“baidu.com”或其子域如“api.baidu.com”、“dev.api.baidu.com”,且 URL 的路径是“/ ”或子路径“/home”、“/home/login”,则浏览器会将此 cookie 添加到该请求的 cookie 头部中。

所以domainpath2个选项共同决定了cookie何时被浏览器自动添加到请求头部中发送出去。如果没有设置这两个选项,则会使用默认值。domain的默认值为设置该cookie的网页所在的域名,path默认值为设置该cookie的网页所在的目录。

特别说明1:
发生跨域xhr请求时,即使请求URL的域名和路径都满足 cookie 的 domain 和 path,默认情况下cookie也不会自动被添加到请求头部中。若想知道原因请阅读本文最后一节)

特别说明2:
domain是可以设置为页面本身的域名(本域),或页面本身域名的父域,但不能是公共后缀 public suffix。举例说明下:如果页面域名为 www.baidu.com, domain可以设置为“www.baidu.com”,也可以设置为“baidu.com”,但不能设置为“.com”或“com”。

secure

secure选项用来设置cookie只在确保安全的请求中才会发送。当请求是HTTPS或者其他安全协议时,包含 secure 选项的 cookie 才能被发送至服务器。

默认情况下,cookie不会带secure选项(即为空)。所以默认情况下,不管是HTTPS协议还是HTTP协议的请求,cookie 都会被发送至服务端。但要注意一点,secure选项只是限定了在安全情况下才可以传输给服务端,但并不代表你不能看到这个 cookie。

下面我们设置一个 secure类型的 cookie:

document.cookie = "name=huang; secure";

之后你就能在控制台中看到这个 cookie 了,如下图所示:

图片描述

这里有个坑需要注意下:
如果想在客户端即网页中通过 js 去设置secure类型的 cookie,必须保证网页是https协议的。在http协议的网页中是无法设置secure类型cookie的。

httpOnly

这个选项用来设置cookie是否能通过 js 去访问。默认情况下,cookie不会带httpOnly选项(即为空),所以默认情况下,客户端是可以通过js代码去访问(包括读取、修改、删除等)这个cookie的。当cookiehttpOnly选项时,客户端则无法通过js代码去访问(包括读取、修改、删除等)这个cookie

在客户端是不能通过js代码去设置一个httpOnly类型的cookie的,这种类型的cookie只能通过服务端来设置。

那我们在页面中怎么知道哪些cookiehttpOnly类型的呢?看下图:

图片描述

凡是httpOnly类型的cookie,其 HTTP 一列都会打上√,如上图中的PA_VTIME。你通过document.cookie是不能获取的,也不能修改PA_VTIME的。

——httpOnly与安全

从上面介绍中,大家是否会有这样的疑问:为什么我们要限制客户端去访问cookie?其实这样做是为了保障安全。

试想:如果任何 cookie 都能被客户端通过document.cookie获取会发生什么可怕的事情。当我们的网页遭受了 XSS 攻击,有一段恶意的script脚本插到了网页中。这段script脚本做的事情是:通过document.cookie读取了用户身份验证相关的 cookie,并将这些 cookie 发送到了攻击者的服务器。攻击者轻而易举就拿到了用户身份验证信息,于是就可以摇摇大摆地冒充此用户访问你的服务器了(因为攻击者有合法的用户身份验证信息,所以会通过你服务器的验证)。

如何设置 cookie?

知道了cookie的格式,cookie的属性选项,接下来我们就可以设置cookie了。首先得明确一点:cookie既可以由服务端来设置,也可以由客户端来设置。

服务端设置 cookie

不管你是请求一个资源文件(如 html/js/css/图片),还是发送一个ajax请求,服务端都会返回response。而response header中有一项叫set-cookie,是服务端专门用来设置cookie的。如下图所示,服务端返回的response header中有5个set-cookie字段,每个字段对应一个cookie(注意不能将多个cookie放在一个set-cookie字段中),set-cookie字段的值就是普通的字符串,每个cookie还设置了相关属性选项。

图片描述

注意:

  • 一个set-Cookie字段只能设置一个cookie,当你要想设置多个 cookie,需要添加同样多的set-Cookie字段。

  • 服务端可以设置cookie 的所有选项:expiresdomainpathsecureHttpOnly

客户端设置 cookie

在网页即客户端中我们也可以通过js代码来设置cookie。如我当前打开的网址为http://dxw.st.sankuai.com/mp/,在控制台中我们执行了下面代码:

document.cookie = "name=Jonh; ";

查看浏览器 cookie 面板如下图所示,cookie确实设置成功了,而且属性选项 domainpathexpires都用了默认值。

图片描述

再执行下面代码:

document.cookie="age=12; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/";

查看浏览器cookie 面板,如下图所示,新的cookie设置成功了,而且属性选项 domainpathexpires都变成了设定的值。

图片描述

注意:

  • 客户端可以设置cookie 的下列选项:expiresdomainpathsecure(有条件:只有在https协议的网页中,客户端设置secure类型的 cookie 才能成功),但无法设置HttpOnly选项。

用 js 如何设置多个 cookie

当要设置多个cookie时, js 代码很自然地我们会这么写:

document.cookie = "name=Jonh; age=12; class=111";

但你会发现这样写只是添加了第一个cookie“name=John”,后面的所有cookie都没有添加成功。所以最简单的设置多个cookie的方法就在重复执行document.cookie = "key=name",如下:

document.cookie = "name=Jonh";
document.cookie = "age=12";
document.cookie = "class=111";

如何修改、删除

修改 cookie

要想修改一个cookie,只需要重新赋值就行,旧的值会被新的值覆盖。但要注意一点,在设置新cookie时,path/domain这几个选项一定要旧cookie 保持一样。否则不会修改旧值,而是添加了一个新的 cookie。

删除 cookie

删除一个cookie 也挺简单,也是重新赋值,只要将这个新cookie的expires 选项设置为一个过去的时间点就行了。但同样要注意,path/domain/这几个选项一定要旧cookie 保持一样。

cookie 编码

cookie其实是个字符串,但这个字符串中逗号、分号、空格被当做了特殊符号。所以当cookie的 key 和 value 中含有这3个特殊字符时,需要对其进行额外编码,一般会用escape进行编码,读取时用unescape进行解码;当然也可以用encodeURIComponent/decodeURIComponent或者encodeURI/decodeURI三者的区别可以参考这篇文章)。

var key = escape("name;value");
var value = escape("this is a value contain , and ;");
document.cookie= key + "=" + value + "; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/";

跨域请求中 cookie

之前在介绍 XHR 的一篇文章里面提过:默认情况下,在发生跨域时,cookie 作为一种 credential 信息是不会被传送到服务端的。必须要进行额外设置才可以。具体原因和如何设置可以参考我的这篇文章:你真的会使用XMLHttpRequest吗?

另外,关于跨域资源共享 CORS极力推荐大家阅读阮一峰老师的这篇 跨域资源共享 CORS 详解

其他补充

  1. 什么时候 cookie 会被覆盖:name/domain/path 这3个字段都相同的时候;

  2. 关于domain的补充说明(参考1/参考2):

    1. 如果显式设置了 domain,则设置成什么,浏览器就存成什么;但如果没有显式设置,则浏览器会自动取 url 的 host 作为 domain 值;

    2. 新的规范中,显式设置 domain 时,如果 value 最前面带点,则浏览器处理时会将这个点去掉,所以最后浏览器存的就是没有点的(注意:但目前大多数浏览器并未全部这么实现)

    3. 前面带点‘.’和不带点‘.’有啥区别:

      • 带点:任何 subdomain 都可以访问,包括父 domain

      • 不带点:只有完全一样的域名才能访问,subdomain 不能(但在 IE 下比较特殊,它支持 subdomain 访问)

总结

咱们今天就聊到这里,若有不对之处欢迎各位指正~~
最后附上一些参考资料:

  1. http://www.quirksmode.org/js/...

  2. http://www.tutorialspoint.com...

  3. http://www.allaboutcookies.or...

  4. http://bubkoo.com/2014/04/21/...

查看原文

无名小贝勒 收藏了问题 · 2019-03-05

ajax跨域请求带上cookie为什么不能用IP?

前端同事访问自己本地的应用 指定了hosts 如

127.0.0.1 my.foo.com

然后访问 my.foo.com 但是在页面上通过ajax调用后端的接口 如调用我机器上的接口

$.ajax({
    type: "post",
    url: 'http://192.169.0.204:8080/bar/search',
    contentType : "application/json;charset=utf-8",
    dataType: "json",
    ...

因为服务端需要获取cookie信息 而这又是跨域调用 默认不带cookie 需要显式设置

client端必须手动设置xhr.withCredentials=true
server端也必须允许request能携带认证信息(即response header中包含Access-Control-Allow-Credentials:true)
server端一定不能将Access-Control-Allow-Origin设置为*,而必须设置为请求页面的域名。
参考: https://segmentfault.com/a/11...

前端和服务端都按上述要求设置了 但是服务端还是接收不到cookie 最后前端同事将我的IP地址也改成hosts 才终于成功了

127.0.0.1 my.foo.com
192.168.0.204 back.foo.com

ajax请求中的地址改成

url: 'http://back.foo.com:8080/bar/search'

我有点不解 都按要求配置了 为什么非得使用hosts呢?用IP为什么就不行呢?

无名小贝勒 赞了回答 · 2019-02-14

egg单元测试怎么测试assert语句?

try {
  abc(arg);
} catch (err) {
  if (err instanceof AssertionError) {
    // 测试通过
    return
  }
}

// 测试不通过

一般测试框架都有针对异常的测试断言方法吧,反正自己做就是try cache一下判断

关注 3 回答 2

无名小贝勒 提出了问题 · 2019-02-14

egg单元测试怎么测试assert语句?

egg应用,某个函数如下:

function abc(arg) {
    assert(typeof arg === 'string', 'arg should be a string');
    
    // do other thing
    // ...
}

如果传参为非string类型,会触发assert语句,控制台报错。测试用例中,怎么写控制台才不会报错呢?

it('should call abc(1) fail', () => {
    // how
});

关注 3 回答 2

无名小贝勒 赞了回答 · 2019-01-02

解决nodejs怎么解压缩zlib格式数据?

一图流

clipboard.png

关注 3 回答 2

无名小贝勒 提出了问题 · 2019-01-02

解决nodejs怎么解压缩zlib格式数据?

如题,node中怎么解压缩zlib格式数据,这里是指某种格式的数据,如zlib,gzip等,不是指node内置的zlib package

关注 3 回答 2

无名小贝勒 评论了文章 · 2018-12-17

从0搭建一个Weex项目

新建项目工程

mkdir weex-starter  
cd weex-starter   
npm init -y   

然后在根目录下新建index.html文件。
目录结构如下:

.
├── index.html
└── package.json

安装依赖

  • webpack & webpack-dev-server
    由于weex-loader暂不支持webpack4,所以,webpack只能安装3.x版本,webpack-dev-server对应安装2.x版本

    npm i webpack@3.x webpack-dev-server@2.x -D
  • babel相关

    npm i babel-loader babel-core babel-preset-env -D
    // 新建.babelrc文件
    {
         "presets": ["env"]
    }
    
  • vue相关

    npm i vue -S
    // vue-loader配置项
    npm i vue-loader autoprefixer postcss-plugin-weex postcss-plugin-px2rem weex-vue-precompiler  -D
  • weex-loader
    weex-loader的作用是把.vue文件转化为native端使用的.weex.js

    npm i weex-loader -D
  • weex-vue-render
    weex-vue-render是 Vue DSL 的 Web 渲染器, 它在 Web 上实现了 Weex 的内置组件和内置模块

    npm i weex-vue-render -S

    此时目录结构如下(忽略node_modules):

    .
    ├── index.html
    ├── package-lock.json
    └── package.json

src目录结构

mkdir -p src/entry src/page

entry文件夹是webpack打包的入口,page文件夹是各个.vue页面。
此时目录结构如下(忽略node_modules):

.
├── index.html
├── package-lock.json
├── package.json
├── src
│   ├── entry
│   └── page
└── webpack.config.js

编写代码

weex最常见的使用场景就是编写某一个页面而不是整个APP,即开发一个一个的页面,然后把这个页面放到native端呈现。所以我们的weex-starter工程也是以页面为单位组织的:src/entry文件夹下,一个入口文件会编译出一个页面。

开发页面是在web端进行的,所以我们要依赖vue和weex-vue-render,但是.weex.js是不需要这两个库的,因为 Weex 本身集成了v2版本的 Vue,而weex-vue-render是 Vue DSL 的 Web 渲染器。开发以及打包编译时,会同时生成.web.js和.weex.js,所以我们把vue和weex-vue-render以<script>标签的方式直接引入到html中。

<!doctype html>
<html>

<head>
  ...
  <script data-original="./node_modules/vue/dist/vue.runtime.min.js"></script>
  <script data-original="./node_modules/weex-vue-render/dist/index.js"></script>
</head>

<body>
  <div id="root"></div>
</body>

</html>
// src/entry/index.js

// import Vue from 'vue/dist/vue.esm'; 
// import weex from 'weex-vue-render';
import Index from '../page/index.vue';

// weex.init(Vue);

Index.el = '#root';
new Vue(Index);

src/page/index.vue就是一个正常的.vue文件,内容自己编写就行。

// webpack.common.js
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');

const entry = {};
...
// 遍历src/entry文件夹下的一级js文件做打包入口,即entry/*.js

const webConfig = {
  entry,
  output: {
    filename: '[name].web.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'dist/'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['babel-loader']
      },
      {
        test: /\.vue(\?[^?]+)?$/,
        use: [
          {
            loader: 'vue-loader',
            options: {
              ...
              // 这个地方的配置参考 https://github.com/weexteam/weex-vue-render
            }
          }
        ]
      }
    ]
  },
  plugins: []
};

const weexConfig = {
  entry,
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['babel-loader']
      },
      {
        test: /\.vue(\?[^?]+)?$/,
        use: ['weex-loader']
      }
    ]
  },
  plugins: [
    // 打包后的.weex.js的头部加上以下banner才能被native识别
    new webpack.BannerPlugin({
      banner: '// { "framework": "Vue" }\n"use weex:vue";\n',
      raw: true
    })
  ]
};

module.exports = [webConfig, weexConfig];

打包编译js分开发环境和生成环境,生成环境,直接打包webpack.common.js的配置就行,每一个页面会打包出对应的.web.js和.weex.js。

// webpack.prod.conf.js
const path = require('path');
const rimraf = require('rimraf');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const commonConfig = require('./webpack.common');

const [webConfig, weexConfig] = commonConfig;

webConfig.plugins.push(new UglifyJSPlugin());
weexConfig.plugins.unshift(new UglifyJSPlugin()); // 是unshift,要先压缩js,后加banner
rimraf.sync(path.resolve(__dirname, 'dist')); // 删除dist文件夹

module.exports = [webConfig, weexConfig];

开发环境时,我们会起一个devServer,server在内存中会生成对应的.web.js,但是此时还需要生成.weex.js,因为开发的时候我们不仅要在web上看效果,还要在native端看效果。

// webpack.dev.conf.js
...

const weexConfig = webpackMerge(commonConfig[1], {
  watch: true
});
// 以Node.js API的方式执行webpack生成weex.js,https://webpack.js.org/api/node/
webpack(weexConfig, (err, stats) => {
  if (err) {
    console.err('COMPILE ERROR:', err.stack);
  }
});

const webConfig = webpackMerge(commonConfig[0], {
  devServer: {
    ...
  }
});

// 寻找可用的端口号
portfinder.getPort((err, port) => {
  if (err) {
    console.log(err);
  } else {
    webConfig.devServer.port = port;
  }
});

module.exports = webConfig;

如果一个工程只能用来开发一张页面未免太奢侈了,所以webpack打包entry配置的是多入口,这样就可以在一个工程里面开发多个页面,想查看不同的页面时,修改一下浏览器的url即可,基于此,做出了以下改动:

// index.html
...
<script>
    // 这段js的意思是:默认加载dist文件夹下的index.web.js,如果想查看另一个页面,把url中的page=index.web.js改成其他的js即可
    // 比如page=home.web.js,此时查看的就是home.vue的内容
    ;(function () {
      var defaultPage = 'index.web.js'

      var match = location.search.match(new RegExp('[?|&]page=([^&]+)'))
      var page = match && match[1]
      if (!page) {
        return location.href = location.href.replace(/\?|$/, function (f) {
          var query = '?page=' + defaultPage
          return f ? query + '&' : query
        })
      }

      var $script = document.createElement('script')
      $script.src = './dist/' + page
      document.body.appendChild($script)
    })();
</script>

此时目录结构如下(忽略node_modules):

.
├── .babelrc
├── index.html
├── package-lock.json
├── package.json
├── src
│   ├── entry
│   │   ├── home.js
│   │   └── index.js
│   └── page
│       ├── home.vue
│       └── index.vue
├── webpack.common.js
├── webpack.dev.conf.js
└── webpack.prod.conf.js

其实,开发weex页面的工程已经完成了,我们实现了一个.vue文件可以打包编译成.web.js和.weex.js。但是,少了一个环节有没有觉察到?——打包出来的.weex.js在native上怎么看页面效果。

native预览

在开发代码时,我们已经动态生成了.weex.js,现在要做的就是把.weex.js以二维码的形式展示出来。
现在是这么简单处理的:在当前页面的左上角上显示了一个二维码,这个二维码的内容正是当前页面对应的.weex.js,然后用 Weex playground app 扫描这个二维码就可以看到页面在手机上渲染的真实效果。

clipboard.png

如果觉得这个二维码在开发的时候有点碍事,想开发一段时间之后再看native预览效果,那你可以先把二维码隐藏掉。

目前的这个效果只是达到了native预览的目的,但是还有很大提升空间。我最终的想法是这样的:页面上有一个类似于苹果手机的虚拟Home键,可以随意拖动,当鼠标hover它上面的时候,会以popover类似的效果展示出二维码。

由于时间比较紧,这个效果并没有开发出来,欢迎提PR,共同完善这个weex-starter工程。github:https://github.com/jasonintju/weex-starter

查看原文

无名小贝勒 评论了文章 · 2018-12-12

阿里、网易、滴滴共十次前端面试碰到的问题

前一段时间一直在不断地面试,无奈个人技术能力有限、项目经验缺乏,最终都没有进入到HR面试环节,全~~挂~~了~~

面试了这么多,结果不是太好,有点儿受打击,也促使我近期静下心来反思自己的问题:哪些技术知识掌握的还不错,哪些还有待提高,哪些是需要去恶补的。

阿里面试了三个部门,都是在二面挂的,网易和滴滴也是各两轮技术面试,加一起就是十次面试经历。在此回忆总结一下,既是给社区朋友的一个参考,反馈社区,更是给自己一个好好的总结。

HTML

  • HTML5新增了哪些内容或API,使用过哪些

  • input和textarea的区别

  • 用一个div模拟textarea的实现

  • 移动设备忽略将页面中的数字识别为电话号码的方法 --- 2017.06.10补充

CSS

  • 左右布局:左边定宽、右边自适应,不少于3种方法

  • CSS3用过哪些新特性

  • BFC、IFC

  • 对栅格的理解

  • (水平)居中有哪些实现方式

  • 1像素边框问题

JavaScript

  • 图片懒加载

  • 实现页面加载进度条

  • 事件委托

  • 实现extend函数

  • 为什么会有跨域的问题以及解决方式

  • jsonp原理、postMessage原理

  • 实现拖拽功能,比如把5个兄弟节点中的最后一个节点拖拽到节点1和节点2之间

  • 动画:setTimeout何时执行,requestAnimationFrame的优点

  • 手写parseInt的实现:要求简单一些,把字符串型的数字转化为真正的数字即可,但不能使用JS原生的字符串转数字的API,比如Number()

  • 编写分页器组件的时候,为了减少服务端查询次数,点击“下一页”怎样能确保还有数据可以加载(请求数据不会为空)?

  • ES6新增了哪些特性,使用过哪些,也有当场看代码说输出结果的

  • JS模块化的实践

  • require.js的实现原理(如果使用过webpack,进一步会问,两者打包的异同及优缺点)

  • promise的实现原理,进一步会问async、await是否使用过

  • 实现gulp的功能

  • 使用前端框架(angular/vue/react)带来哪些好处,相对于使用jQuery

  • vue双向数据绑定的实现

  • 单页应用,如何实现其路由功能

性能优化

  • 项目中使用过哪些优化方法

  • 输入一个URL,Enter之后发生了什么

  • (承上)页面的渲染过程

  • 优化中会提到缓存的问题,问:静态资源或者接口等如何做缓存优化

  • 页面DOM节点太多,会出现什么问题?如何优化?

项目经历

这些大公司招聘都是高级工程师起步,所以对简历上的项目会刨根问底。很多很多问题都是由项目中拓展开的,像优化相关的东西,还有前面提到的require.js、promise、gulp,项目中用到了某项技术,高级工程师的要求是:不仅会用,更要知道其原理。对自己的提醒:项目中用到的技术,不能说完全掌握其原理吧,但大致的实现还是有必要了解一下的。

  • 介绍一下你做的这个项目,进一步细问:整个项目有哪些模块,你主要负责哪些

  • 你在项目中的角色

  • 你在项目中做的最出彩的一个地方

  • 碰到过什么样的困难,怎么解决的

  • (如果你是这个项目的负责人),任务怎么分配的,有没有关注过团队成员的成长问题

  • 前端安全问题:CSRF和XSS

其他

  • 为什么选择做前端(我靠,我都快转前端两年了,还在问这个问题啊...)

  • 你希望进入一个什么样的团队

  • 你有什么问题想问我(面试官)的吗?


前前后后有两个月时间,暂时只回忆起这么多了,如果还有其他的,后期我会补上。

webpack其实也是必问的,由于我说还没使用过webpack,只是了解,写过demo,面试官就没问太深。如果你的简历中有提到webpack,请提前准备好,比如webpack打包原理、如何写webpack插件等。

面试阿里云那个岗位的时候,有要求算法和数据结构,有能力者多多准备吧。

阿里、网易的面试几乎都是围绕项目展开的,所以提醒自己搬砖的时候多想想、多看看,多站在一个高度去看整个项目:用到什么技术,技术实现原理是什么,项目框架怎么搭建的,采取安全措施了吗...


后记

有几个岗位感觉就是挂在了项目上。自己做过一个前后端分离项目,但是经过几次面试,发现这个项目还存在某些问题,比如:整个登录注册系统是不完善的,关于权限的处理上甚至是有很大缺陷的;这个项目的node层只是起到构建前端项目(gulp)、渲染index.ejs、代理转发api接口等作用,但是面试官指出说你这个node也太简单了,导致我都在怀疑这是个假的前后端分离...还是需要大神带多见见世面啊,求带...

虽然五次面试都没成功,但自己也收获了很多很多:认识了大牛hb,一个超有文艺气息的资深前端;多谢fw大大帮我内推阿里,十分感谢您对我的认可;也见到了平时只能在视频上看到的cjf老师,谢谢您的指点;对高级前端工程师所具备的技能有了更清晰的认识;肯定也增加了很多面试经验...

再好好提升一下,打算过段时间重新上阵,也祝自己多点好运气,早日进入心仪的企业,毕竟,当初来杭州的时候就是以网易、阿里为目标的。

查看原文

无名小贝勒 赞了问题 · 2018-11-28

ajax跨域请求带上cookie为什么不能用IP?

前端同事访问自己本地的应用 指定了hosts 如

127.0.0.1 my.foo.com

然后访问 my.foo.com 但是在页面上通过ajax调用后端的接口 如调用我机器上的接口

$.ajax({
    type: "post",
    url: 'http://192.169.0.204:8080/bar/search',
    contentType : "application/json;charset=utf-8",
    dataType: "json",
    ...

因为服务端需要获取cookie信息 而这又是跨域调用 默认不带cookie 需要显式设置

client端必须手动设置xhr.withCredentials=true
server端也必须允许request能携带认证信息(即response header中包含Access-Control-Allow-Credentials:true)
server端一定不能将Access-Control-Allow-Origin设置为*,而必须设置为请求页面的域名。
参考: https://segmentfault.com/a/11...

前端和服务端都按上述要求设置了 但是服务端还是接收不到cookie 最后前端同事将我的IP地址也改成hosts 才终于成功了

127.0.0.1 my.foo.com
192.168.0.204 back.foo.com

ajax请求中的地址改成

url: 'http://back.foo.com:8080/bar/search'

我有点不解 都按要求配置了 为什么非得使用hosts呢?用IP为什么就不行呢?

关注 3 回答 2

认证与成就

  • 获得 926 次点赞
  • 获得 129 枚徽章 获得 11 枚金徽章, 获得 45 枚银徽章, 获得 73 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

注册于 2015-08-07
个人主页被 4.5k 人浏览