This is the 29th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021.”

preface

Before is busy with business development, the basic knowledge of front end to check what are used, rarely has time to sink down and their induction, summarizes the basis, sometimes, what use, feel worthy of pay attention to the thing, are also recorded in his note, also not timely, and then as time goes by, one record everything is at sixes and sevens, I haven’t done it yet. This time, write the basic series of the front end

I plan to chat in a relaxed, chatty tone. If I’m not good at writing, I’ll let you know

Quickly review

Above,

  1. modular
  2. proxy
  3. map, filter, reduce

Concurrency is different from parallelism

These two nouns are indeed a lot of people often confused knowledge. In fact, the reason for the confusion may simply be that the two nouns are similar in Chinese but completely different in English.

Concurrency is A macro concept. I have task A and task B, respectively, and I complete these two tasks by switching between tasks within A period of time. This situation can be called concurrency.

Parallelism is A microscopic concept, assuming that there are two cores in the CPU, then I can complete task A and TASK B simultaneously. Parallelism is when multiple tasks are performed simultaneously.

Callback function

The following code is an example of a callback function:

ajax(url, () = > {
    // Process logic
})
Copy the code

But Callback functions have a fatal flaw: they are easy to write Callback hell. Assuming multiple requests have dependencies, you might write code like this:

ajax(url, () = > { 
    // Process logic
    ajax(url1, () = > { 
        // Process logic
        ajax(url2, () = > { 
        // Process logic})})})Copy the code

The above code may seem unreadable and unmaintainable, but of course, you might be tempted to say that the solution to this problem is not as simple as writing the functions separately

function firstAjax() { 
    ajax(url1, () = > { 
        // Process logic
        secondAjax()
    })
}

function secondAjax() { 
    ajax(url2, () = > { 
        // Process logic
    })
}

ajax(url, () = > { 
    // Process logic
    firstAjax() 
})
Copy the code

The above code, while seemingly easy to read, does not address the root of the problem.

The fundamental problem with callback hell is this:

  1. Nested functions are coupled and can be affected by changes
  2. Multiple nested functions make it difficult to handle errors

Of course, callback functions have several other drawbacks, such as the inability to catch errors using a try catch and the inability to return directly. In the following sections, we’ll look at other techniques to solve these problems.

Generator

Generator is one of the most difficult concepts to understand in ES6. The most important feature of Generator is that it can control the execution of functions. In this section we won’t go into what a Generator is, but rather focus on some of the confusing aspects of generators.

function *foo(x) { 
    let y = 2 * (yield (x + 1)) 
    let z = yield (y / 3) 
    return (x + y + z)
}

let it = foo(5) 
console.log(it.next()) // => {value: 6, done: false} 
console.log(it.next(12)) // => {value: 8, done: false} 
console.log(it.next(13)) // => {value: 42, done: true}
Copy the code

You may be wondering why the value is different from what you expected, so let me break it down for you line by line

  • First of all,GeneratorA function call, unlike a normal function, returns an iterator
  • When performing the firstnextIs ignored, and the function pauses atyield (x + 1), so return5 plus 1 is 6
  • When executed the second timenextWhen, the argument passed is equal to the previous oneyieldIf you do not pass the parameter,yieldNever returnundefined. At this timelet y = 2 * 12So the second oneyieldIs equal to the2 times 12/3 is 8
  • When executing the third timenextIs passed toz, soz = 13, x = 5, y = 24Add up to42

Generator functions are not commonly seen, and are generally used with co libraries. Of course, we can solve the problem of callback hell with Generator functions. We can rewrite the previous callback hell example as follows:

function *fetch() { 
    yield ajax(url, () = > {}) 
    yield ajax(url1, () = > {}) 
    yield ajax(url2, () = >{})}let it = fetch() 
let result1 = it.next() 
let result2 = it.next() 
let result3 = it.next()
Copy the code

Promise

A Promise translates to a Promise that there will be a definite answer in the future, and the Promise has three states:

  1. Pending
  2. Completed (Resolved)
  3. I have rejected your offer.

This promise can never be changed once it has gone from waiting to another state, which means it can’t be changed again once it has become resolved

new Promise((resolve, reject) = > { 
    resolve('success') 
    // If you want to change a state, it is invalid. The following line is invalid
    reject('reject')})Copy the code

When we construct a Promise, the code inside the constructor executes immediately

new Promise((resolve, reject) = > { 
    console.log('new Promise') 
    resolve('success')})console.log('finifsh') // new Promise -> finifsh
Copy the code

Promise implements chained invocation, which means that each call to THEN returns a Promise, and a new Promise, again because the state is immutable. If you use return in then, the value of return is wrapped in promise.resolve ()

Promise.resolve(1)
    .then(res= > { 
        console.log(res) / / = > 1
        return 2 // wrap as promise.resolve (2)
    })
    .then(res= > { 
        console.log(res) / / = > 2
    })
Copy the code

Of course, Promise solves the problem of callback hell nicely by rewriting the previous callback hell example into code like this:

ajax(url)
    .then(res= > { 
        console.log(res) 
        return ajax(url1) 
    })
    .then(res= > { 
        console.log(res) 
        return ajax(url2)
    }).then(res= > console.log(res))
Copy the code

The advantages and features of Promises are described above, but there are also some disadvantages, such as the inability to cancel promises, and errors that need to be caught through callback functions.

Async and await

If async is added to a function, the function returns a Promise

async function test() { 
    return "1" 
} 

console.log(test()) // -> Promise {<resolved>: "1"}
Copy the code

Async wraps the return value of a function in promise.resolve (), as in then, and await can only be used with async

async function test() { 
    let value = await sleep() 
}
Copy the code

Async and await are the ultimate solution to asynchrony. The advantage is to handle the chain of then calls and write code more clearly and accurately than using promises directly. After all, writing a lot of THEN calls is disgusting, and the callback hell problem is solved elegantly. Of course, there are some disadvantages, because await transforms asynchronous code into synchronous code, and if multiple asynchronous code uses await without dependencies, it will result in performance degradation.

async function test() { 
    // If the following code does not have dependencies, you can use promise.all
    // If there is a dependency, it is an example of solving callback hell
    await fetch(url) 
    await fetch(url1) 
    await fetch(url2) 
}
Copy the code

Let’s look at an example of using await:

let a = 0 
let b = async () => { 
    a = a + await 10 
    console.log('2', a) / / - > '2' 10
} 

b() 
a++ 
console.log('1', a) / / - > '1' 1
Copy the code

You may be confused by the above code, but let me explain why

  • The first functionbExecute first, and then execute toawait 10Before the variableaIt’s still 0 becauseawaitInternally implementedgenerator ,generatorIt’s going to keep stuff in the stack, so at this pointa = 0It’s been preserved
  • becauseawaitIs an asynchronous operation, and subsequent expressions do not returnPromiseIf so, it will be packaged asPromise.reslove(return value)“, and then executes synchronized code outside the function
  • After the synchronous code is finished, the asynchronous code is executed and the saved value is taken out for usea = 0 + 10

“Await” is a syntactic sugar of generator plus Promise, and “automatic execution generator” is implemented inside. If you are familiar with CO, you can actually implement such syntactic sugar yourself.

Common timer function

Asynchronous programming, of course, requires timers. Common timer functions include setTimeout, setInterval, and requestAnimationFrame. Let’s first talk about the most commonly used setTimeout. Many people think that setTimeout should be executed after as long as it is delayed.

This is not true because JS is executed in a single thread, and if the previous code affects performance, setTimeout will not execute on schedule. Of course, we can fix setTimeout in code to make the timer relatively accurate

let period = 60 * 1000 * 60 * 2 
let startTime = new Date().getTime() 
let count = 0 
let end = new Date().getTime() + period 
let interval = 1000 
let currentInterval = interval 

function loop() { 
    count++ // The time taken by code execution
    let offset = new Date().getTime() - (startTime + count * interval);
    let diff = end - new Date().getTime() 
    let h = Math.floor(diff / (60 * 1000 * 60)) 
    let hdiff = diff % (60 * 1000 * 60) 
    let m = Math.floor(hdiff / (60 * 1000)) 
    let mdiff = hdiff % (60 * 1000) 
    let s = mdiff / (1000) 
    let sCeil = Math.ceil(s) 
    let sFloor = Math.floor(s) // Get the time for the next loop
    currentInterval = interval - offset console.log(':'+h, ':'+m, 'milliseconds:'+s, 'Seconds rounded up:'+sCeil, 'Code execution time:'+offset, 'Next cycle interval'+currentInterval) 
    
    setTimeout(loop, currentInterval)
} 

setTimeout(loop, currentInterval)
Copy the code

SetInterval is basically the same as setTimeout, except that it executes a callback every once in a while.

SetInterval is generally not recommended. First, it, like setTimeout, is not guaranteed to execute the task at the expected time. Second, it has the problem of performing accumulation, as shown in the pseudo-code below

function demo() { 
    setInterval(function(){ 
        console.log(2)},1000)
    sleep(2000)
}

demo()
Copy the code

In the browser environment, if a time-consuming operation occurs during the timer execution, multiple callback functions will be executed at the same time after the time-consuming operation, which may cause performance problems.

If you need a loop timer, you can use requestAnimationFrame to do it

function setInterval(callback, interval) { 
    let timer const now = Date.now 
    let startTime = now() 
    let endTime = startTime 
    const loop = () = > { 
        timer = window.requestAnimationFrame(loop) 
        endTime = now() 
        if (endTime - startTime >= interval) { 
            startTime = endTime = now() 
            callback(timer) 
        }
    } 
    
    timer = window.requestAnimationFrame(loop) 
    return timer
} 

let a = 0 
setInterval(timer= > { 
    console.log(1) 
    a++ 
    if (a === 3) cancelAnimationFrame(timer)
}, 1000)
Copy the code

RequestAnimationFrame has its own function throttling function, which can be executed only once in 16.6 ms (without dropping frames), and the delay effect of this function is accurate. There are no other timer errors. Of course, you can also use this function to implement setTimeout.

conclusion

  1. Concurrency is different from parallelism
  2. Callback function
  3. Generator
  4. Promise
  5. Async and await
  6. Common timer function

Ps: Dry words or more boring, and hard to impress, we are still in daily use, more experience