Hi everyone, I am HuiAzir, here to share with you my interview experience in Ali
Technical summary
At the beginning, I was still very nervous. Fortunately, the interviewer was very kind π and the tension soon disappeared. Don’t say much, see experience directly π!
Interviewer π¨: Let me introduce myself π.
I πΆπ»: I am a junior student of Harbin Institute of Technology, and I have done balabala…., XXX project in my school , currently working as an intern in JINGdong, doing XXX project, Balabala… I started to learn front-end Balabala in sophomore year. (Here I mainly describe my current situation, project experience, and how to learn the front end) π
Interviewer π¨: I see that both Vue and React are used in your project. I want to ask you a question about Vue. How does Vue listen for data changes and trigger view updates?
The core of this is Object.defineProperty(). Proxy has been used in Vue3.0.
Here I would like to share with you a simple MVVM framework I once implemented when LEARNING Vue principles. Step by step analysis will soon be understood.
class MVVM {
// Initialize some data in the constructor, and delegate computed and methods to this.
constructor(options) {
this.$vm = this;
this.$el = options.el;
this.$data = options.data;
let computed = options.computed;
let methods = options.methods;
if (this.$el) {
// Make the data observable
new Observer(this.$data);
for (let key in computed) {
Object.defineProperty(this.$data, key, {
get() {
return computed[key].call(this); }}); }for (let key in methods) {
Object.defineProperty(this, key, {
get() {
return methods[key].bind(this); }}); }// Template compilation
new Compiler(this.$vm, this.$el); }}}// This is the class that makes data observable
class Observer {
constructor(data) {
this.observer(data);
}
observer(data) {
if (data && Object.prototype.toString.call(data) === '[object Object]') {
for (let key in data) {
this.defineReactive(data, key, data[key]);
}
}
}
defineReactive(obj, key, value) {
const self = this;
this.observer(value);
let dep = new Dep();
Object.defineProperty(obj, key, {
// The current observer is stored in the subscription container when data gets
get() {
Dep.target && dep.addSub(Dep.target);
return value;
},
// When data is reset, inform the subscriber that it is ready to update!
set(newValue) {
if(value ! == newValue) { self.observer(newValue); value = newValue; dep.notify(); }}}); }}// Subscribe to the container
class Dep {
// Temporarily store the static properties of the current observer
static target = null;
constructor() {
this.subs = [];
}
// Add subscribers
addSub(watcher) {
this.subs.push(watcher);
}
// Notification update
notify() {
this.subs.forEach(watcher= >watcher.update()); }}// Observer class
class Watcher {
constructor(vm, expr, cb) {
this.vm = vm;
this.expr = expr;
this.cb = cb;
this.oldValue = this.getVal();
}
getVal() {
Dep.target = this;
let value = compileUtils.getVmData(this.vm, this.expr);
Dep.target = null;
return value;
}
// Each observer must have an update function to trigger the view update callback
update() {
let newValue = this.getVal();
this.cb(newValue); }}class Compiler {
constructor(vm, el) {
this.vm = vm;
this.el = this.isElementNode(el) ? el : document.querySelector(el);
let fragment = this.nodeToFragment(this.el);
this.compile(fragment);
this.el.appendChild(fragment);
}
isElementNode(node) {
return node.nodeType === Node.ELEMENT_NODE;
}
isDirective(attrName) {
return attrName.startsWith('v-');
}
nodeToFragment(node) {
let fragment = document.createDocumentFragment();
let firstChild;
while ((firstChild = node.firstChild)) {
fragment.appendChild(firstChild);
}
return fragment;
}
compile(node) {
let childNodes = [...node.childNodes];
childNodes.forEach(childNode= > {
if (this.isElementNode(childNode)) {
this.compileElementNode(childNode);
this.compile(childNode);
} else {
this.compileTextNode(childNode); }}); } compileElementNode(node) {let attrs = [...node.attributes];
attrs.forEach(({ name, value: expr }) = > {
if (this.isDirective(name)) {
let [, directive] = name.split(The '-');
let [directiveName, event] = directive.split(':');
compileUtils[directiveName](this.vm, expr, node, event); }}); } compileTextNode(node) {let reg = new RegExp(/ \ {\ {(. *?) \}\}/g);
if (reg.test(node.textContent)) {
compileUtils.text(this.vm, node); }}}// Here are some of the utility functions needed to compile templates
compileUtils = {
getVmData(vm, expr) {
return expr.split('. ').reduce((data, current) = > {
return data[current];
}, vm.$data);
},
on(vm, expr, node, event) {
node.addEventListener(event, e => {
vm[expr](e);
});
},
model(vm, expr, node) {
let value = this.getVmData(vm, expr);
node.addEventListener('input', e => {
expr.split('. ').reduce((data, current, index, arr) = > {
if (index === arr.length - 1) {
return (data[current] = e.target.value);
}
return data[current];
}, vm.$data);
});
// Create an observer wherever data is used
new Watcher(vm, expr, newValue => {
this.update.model(node, newValue);
});
this.update.model(node, value);
},
text(vm, node) {
let oldContent = node.textContent;
let reg = new RegExp(/ \ {\ {(. *?) \}\}/g);
letnewContent = oldContent.replace(reg, (... args) => {// Create an observer wherever data is used
new Watcher(vm, args[1], () = > {letnewContent = oldContent.replace(reg, (... args) => {return this.getVmData(vm, args[1]);
});
this.update.text(node, newContent);
});
return this.getVmData(vm, args[1]);
});
this.update.text(node, newContent);
},
update: { model(node, value) { node.value = value; }, text(node, content) { node.textContent = content; }}};Copy the code
It’s easy to use
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model="msg">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<div>{{msg}}</div>
<div>
<p>{{a}}</p>
</div>
</div>
<script src="./MVVM.js"></script>
<script>
let vm = new MVVM({
el: '#app'.data: {
msg: 'a'.a: 'hello'}})</script>
</body>
</html>
Copy the code
Interviewer π¨: Your resume says you know something about ES6. Can you tell me something about asynchronous requests in ES6? And what problems did it solve?
I πΆπ»: ES6’s asynchronous requests are done using chained calls of Promise, mainly to solve the problem of callback hell. Callback hell is when callback functions are nested so deeply that the code is difficult to read and maintain.
Interviewer π¨: Can you talk about the principle of Promise?
Here I also share my Promise of pure masturbation.
class Promise {
PENDING = 'pending';
RESOLVED = 'resolved';
REJECTED = 'rejected';
static resolve = value= > {
return new Promise((resolve, reject) = > {
try {
if (value instanceof Promise) {
value.then(resolve, reject);
} else{ resolve(value); }}catch(error) { reject(error); }}); };static reject = reason= > {
return new Promise((resolve, reject) = > {
reject(reason);
});
};
static all = promises= > {
let count = 0;
let values = [];
const promisesLength = promises.length;
return new Promise((resolve, reject) = > {
promises.forEach((p, index) = > {
Promise.resolve(p).then(
value= > {
count++;
values[index] = value;
if(count === promisesLength) { resolve(values); } }, reason => { reject(reason); }); }); }); };static race = promises= > {
return new Promise((resolve, reject) = > {
promises.forEach(p= > {
Promise.resolve(p).then(resolve, reject);
});
});
};
constructor(executor) {
this.status = this.PENDING;
this.data = undefined;
this.cbs = [];
const resolve = value= > {
if (this.status === this.PENDING) {
this.status = this.RESOLVED;
this.data = value;
setTimeout((a)= > {
this.cbs.forEach(cbObj= > {
cbObj.onResolved(this.data);
});
this.cbs = []; }); }};const reject = reason= > {
if (this.status === this.PENDING) {
this.status = this.REJECTED;
this.data = reason;
setTimeout((a)= > {
this.cbs.forEach(cbObj= > {
cbObj.onRejected(this.data);
});
this.cbs = []; }); }};try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value= > value;
onRejected =
typeof onRejected === 'function'
? onRejected
: reason= > {
throw reason;
};
const self = this;
return new Promise((resolve, reject) = > {
const handle = cb= > {
try {
const result = cb(self.data);
if (result instanceof Promise) {
result.then(resolve, reject);
} else{ resolve(result); }}catch(error) { reject(error); }};if(self.status === self.PENDING) { self.cbs.push({ onResolved() { handle(onResolved); }, onRejected() { handle(onRejected); }}); }else if (self.status === self.RESOLVED) {
setTimeout((a)= > {
handle(onResolved);
});
} else if (self.status === self.REJECTED) {
setTimeout((a)= >{ handle(onRejected); }); }}); }catch(onRejected) {
return this.then(null, onRejected); }}Copy the code
Interviewer π¨: Looking at your resume, you have been building your own component library recently, right? Use React Hooks. Why are React Hooks created, and what problems do they solve?
I πΆ π» :
In the past, the way we built the React component was coupled to the component lifecycle. This causes the component to be interspersed with related logic. For example, if a listener is bound to componentDidmount, it should be released in componentWillUnmount. This is done in hooks
useEffect((a)= >{
// Listen on events. return ()=>{// Unbind events. }})Copy the code
Interviewer π¨: Ok, so if I wanted you to make a popover widget right now, what would you do?
I πΆπ»: React provides an API that Portals can mount a component under the body.
Interviewer π¨: Can you tell me why you want to mount it under the body?
I πΆπ»: one is to make the order of HTML tags more logical, and the other is not to affect the parent component of the pop-up component.
Interviewer π¨: Seeing that your project uses React Hooks + Mobx, can you talk about how Hooks and Mobx are connected?
I πΆπ»: Now let Mobx export a store, use createContext to store the exported store, and then use useContext to wrap the component with observe provided by Mobx-React-Lite.
Interviewer π¨: Can you tell me how Mobx works?
I πΆπ»: I have not known about this, but I am currently analyzing the source code of Vue and React, and I will read the source code of their surrounding ecology later.
Interviewer π¨: I see your resume says that you are familiar with Webpack. How familiar are you? What are the main problems that WebPack solves?
I πΆπ»: can implement the basic scaffolding configuration of the project and do some performance optimization for the Webpack packaging process. The main problem webpack solves is to analyze the project structure, find JavaScript modules and other extension languages that browsers don’t run directly, and convert and package them into appropriate formats for browsers to use.
Interviewer π¨: Ok, so if the project is packaged and live, how do you let the user know that the file is updated without using cache?
[contexthash:8].js. The webpack configuration is as follows: [name].[contexthash:8].js
Interviewer π¨: Can you tell me a little bit about HTTP caching?
I πΆ π» :
Strong cache
Strong caching can be implemented by setting two HTTP headers: Expires and CacheControl. Strong caching means that no request is required during caching, with a state code of 200
Expires: Wed, 22 Oct 2018 08:41:00 GMT
Expires is a result of HTTP/1, indicating that a resource Expires after Wed, 22 Oct 2018 08:41:00 GMT and needs to be requested again. In addition, Expires is limited to local time, and changing the local time can invalidate the cache.
Cache-control: max-age=30
- Cache-control appears in HTTP/1.1 and takes precedence over Expires. The value of this attribute indicates that the resource will expire after 30 seconds and needs to be requested again.
- Cache-control can be set in either the request header or the response header, and multiple instructions can be combined
Negotiate the cache
- If the cache expires, a request needs to be made to verify that the resource has been updated. Negotiated caching can be implemented by setting two HTTP headers: Last-Modified and ETag
- When the browser makes a request to validate the resource, if the resource has not changed, the server returns a 304 status code and updates the browser cache validity period.
The last-modified and If – Modified – Since
Last-modified indicates the Last Modified date of the local file. If-modified-since will send the last-modified value to the server and ask the server If the resource has been updated Since this date. If it has been updated, the new resource will be sent back, otherwise 304 will be returned.
But last-Modified has some drawbacks:
- If a cached file is opened locally, last-Modified changes are made even if the file is not Modified, and the server fails to match the cache and sends the same resource
- Because last-Modified can only be measured in seconds, if the file is Modified in an imperceptible amount of time, the server will assume that the resource is still hit and will not return the correct resource. This is why ETag was introduced in HTTP / 1.1
The ETag and If – None – Match
An ETag is similar to a file fingerprint. If-none-match sends the current ETag to the server, asking If the ETag of the resource has changed, and sending the new resource back If it has changed. And the ETag priority is higher than Last Modified.
Interviewer π¨: How do you plan to learn the front-end in depth in the future?
πΆ : First, learn the source code of React and Vue, and then learn the source code of their surrounding ecology, and then combine more project experience to further learn front-end engineering.
Interviewer π¨: Ok, that’s all for today. Do you have any questions for me?
I πΆ : I would like to ask you to recommend some information about the micro front end, want to understand the knowledge of the micro front end.
Here the interviewer told me a lot, micro front-end is also just emerging things, the information is not a lot, if you can come to Ali, can provide you with internal reference, can also participate in the project, Ali also has a lot of practice in this area…… . I generally conclude that the micro front end may not be the inevitable trend in the future, and it will be up to the project to decide whether to implement the micro front end architecture. π
Summary of Project experience
Tao department of technology more value project experience, especially the project has any special bright spot, unfortunately, I really can not sum up the project I have done in addition to a little performance optimization and what bright spot, the project is relatively ordinary.
conclusion
I met a total of 8 people in Ali, including 3 tao department and 5 rookie, and finally got the rookie offer. During the interview, the interviewers were very kind and did not give me any psychological pressure. In these interviews, I found that I still lacked the understanding of principles and the creativity of the project. In the future, I will study more fundamental things and improve my creativity. Ollie here!! π π» π πΎ π π πΏ π π½ π πΌ