Revision Note: After the release of “JS interview questions that 80% applicants fail”, the total number of net reading more than 6W, zhihu, Nuggets, CnodeJS have triggered a lot of discussions, but also by a number of front-end wechat official accounts and technical media. After brewing for a long time, the front facet of the author to write next paper series, covering the DOM, HTTP, browser, framework, coding, engineering, etc., on the one hand to cover students combing interview, understanding key front knowledge context, on the other hand also give the interviewer counterparts do reference, how to design the distinguished interview questions. This article is a revised reissue of the first article, students who have read it can not read it again, interested in the supplement 1, the follow-up article will be published in Zhihu, Nuggets, cnodeJS synchronous.
The 3,599 characters take seven minutes to read and three minutes to speed read. In my 2 + years as an interviewer, I interviewed over 200 front-end engineers and was surprised to find that more than 80% of the candidates failed a passing grade on the following closure/timer questions. What kind of magical interview question is this? What abilities does he look for in candidates? What does that mean for you as you read this? Just listen to me slowly.
Humble beginnings
Recruitment of front-end engineers, especially senior front-end engineers, a solid JS foundation is absolutely necessary, the foundation is not solid engineers in the face of various problems in the front-end development of large probability will be at a loss. When looking at a candidate’s JS base, I often provide the following code and ask the candidate to analyze the result in action:
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
console.log(new Date, i);Copy the code
This is a very short code, it’s only seven lines, and I don’t think anyone who can read this needs me to explain what this code is doing line by line. Candidates give different results when presented with this code, and here’s a typical answer:
- A. 20% of people scan the code quickly and give the result:
0,1,2,3,4,5
; - B. 30% of people take the code line by line and give the result:
5,0,1,2,3,4
; - C. 50% of the people take the code and chew it over and come up with the result:
5,5,5,5,5,5
;
The correct answer is C, as long as you understand the difference between synchronous and asynchronous code in JS, variable scope, closure, etc.
2017-03-18T00:43:45.873z 5 2017-03-18T00:43:46.866z 5 2017-03-18T00:43:46.868z 5 2017-03-18T00:43:46.868z 5 2017-03-18T00:43:46.868z 5 2017-03-18T00:43:46.868z 5 2017-03-18T00:43:46.868z 5 2017-03-18T00:43:46.868z 5 2017-03-18T00:43:46.868z 5 2017-03-18T00:43:46.868z 5 The 2017-03-18 T00:43:46. 868 z 2017-03-18 T00:43:46. 868 zCopy the code
Next, I ask: What if we agreed that an arrow indicated that the interval between the two outputs was 1 second, and a comma indicated that the interval between the two outputs was negligible? There are two answers:
- A. 60% would describe it as:
5 -> 5 -> 5 -> 5 -> 5
, that is, there is a 1 second interval between each 5; - B. 40% would describe it as:
5 - > 5,5,5,5,5
, that is, the first 5 is printed directly. After 1 second, 5 5 are printed.
This requires the candidate to be very familiar with the working mechanism of timers in JS. During the cycle execution, 5 timers are almost set at the same time. Under normal circumstances, these timers will be triggered after 1 second, and the output of the cycle is executed immediately.
If this is a passing grade, 20 out of 100 people will pass the interview, so those of you reading this can think about it, did you pass?
Question 1: Closures
5 -> 0,1,2,3,4, 5 -> 0,1,2,3,4 Those familiar with closures will quickly come up with the following solutions:
for (var i = 0; i < 5; i++) {
(function(j) { // j = i
setTimeout(function() {
console.log(new Date, j);
}, 1000);
})(i);
}
console.log(new Date, i);Copy the code
Elegant use of IIFE (Immediately Invoked Function Expression: It’s a good idea to solve the problem caused by closures, but the code may not be easy for beginners to understand, at least when I first started thinking about it.
Add: If a student gives the following solution, it indicates that he is a person who carefully reads THE API documentation. This habit will help him avoid detours when learning. The code is as follows:
for (var i = 0; i < 5; i++) {
setTimeout(function(j) {
console.log(new Date, j);
}, 1000, i);
}
console.log(new Date, i);Copy the code
Is there something more intuitive to do? The answer is yes, we just need to tweak the body of the loop so that the output code gets the I value for each loop. How do you do that? By taking advantage of the Primitive Type in JS that is passed by Value, it is not difficult to modify the following code:
var output = function (i) { setTimeout(function() { console.log(new Date, i); }, 1000); }; for (var i = 0; i < 5; i++) { output(i); } console.log(new Date, I);} console.log(new Date, I);Copy the code
Candidates who can provide the above two solutions are considered to have a good understanding of the basics of JS and will receive 10 points for each. Of course, some candidates give the following code in the actual interview:
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
console.log(new Date, i);Copy the code
Careful students will notice that there is only one very subtle change: var is replaced by let in ES6 Block Scope, but the code will actually run with an error because the last output uses an I that does not exist in its Scope; I only exists inside the loop.
Students who can think of ES6 features did not answer correctly, but showed their understanding of ES6, can add 5 points, continue to follow the question.
Follow-up 2: ES6
Experienced front end students read here may be a little impatient, pulled so much, is he knows the content, don’t worry, the challenge will continue to increase.
If you want the output to be 0 -> 1 -> 2 -> 3 -> 4 -> 5, and you want the loop and two console. logs in the original code block to remain unchanged, how do you change the code? The new requirements can be accurately described as: When the code is executed, output 0 immediately, and then output 1,2,3,4 every second. At the end of the cycle, output 5 at about the fifth second (use about here, is to avoid the students stuck in the trap, because the timer trigger time in JS may be uncertain, For details, see How Javascript Timers Work).
Seeing this, some of you will give the following possible solution:
for (var i = 0; i < 5; i++) { (function(j) { setTimeout(function() { console.log(new Date, j); }, 1000 * j); })(I); } setTimeout(function() {console.log(new Date, I);} setTimeout(function() {console.log(new Date, I); }, 1000 * i);Copy the code
Admittedly, this is crude and effective, but it’s not exactly a bonus. How would the code be organized if you abstracted the requirement to do something else after a series of asynchronous operations (one asynchronous operation per loop) were completed? Are you wise enough to remember something? Yeah, Promise.
Some students might ask, isn’t it just output a few numbers on the console? As for killing chickens like this? You know, what the interviewer is really looking for is the ability and quality of the candidate, because in modern front-end development, asynchronous code is ubiquitous, and familiarity with the flow control of asynchronous operations is essential to becoming a qualified developer.
Along the way, it’s not hard to come up with a promise-based solution (since Promises are a new feature in ES6, wouldn’t our new code be better written in ES6? Your interviewer will most likely like you if you do:
const tasks = []; for (var i = 0; i < 5; I ++) {// the declaration of I cannot be changed to let. ((j) => { tasks.push(new Promise((resolve) => { setTimeout(() => { console.log(new Date, j); resolve(); // resolve, otherwise the code will not work as expected. // The timer time gradually increases})); })(i); } Promise.all(tasks).then(() => { setTimeout(() => { console.log(new Date, i); }, 1000); // Note that you only need to set timeout to 1 second});Copy the code
In comparison, I prefer the following code which looks more concise. You should know that the programming style is also the point that many interviewers focus on. The smaller granularity and better modularity of code reading will undoubtedly be a plus point.
const tasks = []; // Const output = (I) => new Promise((resolve) => {setTimeout(() => {console.log(new Date, I); resolve(); }, 1000 * i); }); For (var I = 0; i < 5; i++) { tasks.push(output(i)); All (tasks).then(() => {setTimeout(() => {console.log(new Date, I); }, 1000); });Copy the code
For those of you reading this, congratulations, your next interview with a similar question will get at least 80 points.
We all know that using promises to deal with asynchronous code makes it more readable than the callback mechanism, but the problem with using Promises is that if you don’t deal with Promise reject, errors are thrown into a black hole. The good news is that newer Versions of Chrome and Node 7.x have an Unhandled Rejection Warning for exceptions that have not been handled, and it takes some special tricks (browser, Node.js) to handle them.
Follow-up 3: ES7
Now that you’ve seen this, hold on for another two minutes, and the rest of this will show you that it was worth it.
Most interviewers before decide to hire a candidate also need to inspect another important ability, namely technology since the drive, bluntly said is internal candidate as a motor to drive him, with a beautiful way to solve the problem of engineering field, with business and technology becomes more and more cow force, what is cool? I suggest reading this profile of Programlife.
Back to the point, now that the Promise has been taken down, how can I use the async/await feature in ES7 to make this code more concise? Can you give an answer based on what you know so far? Pause here for a minute and think about it.
The following is the reference code given by the author:
Const sleep = (timeountMS) => new Promise((resolve) => {setTimeout(resolve, timeountMS); }); (async () => {// declare async function expression for (var I = 0; i < 5; i++) { if (i > 0) { await sleep(1000); } console.log(new Date, i); } await sleep(1000); console.log(new Date, i); }) ();Copy the code
conclusion
Thank you take time to read this, I believe you harvest is not only use JS precise control digital output a variety of skills, but behind all kinds of skills and knowledge from the macro level, is to clear the front qualified engineer should have the characteristics: the solid language foundation, advancing with The Times since the drive ability, strong technology, see future articles.
One More Thing
The author of this article is Wang Shijun. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source. If you found this article helpful, please give it a thumbs up! If you have any questions about the content of this article, please leave a comment. Want to know what I’ll write next? Welcome to subscribe to nuggets column or Zhihu column: “Front End Weekly: Keep you up to date in the front end field”.