JavaScript is a single-threaded language, meaning that you can only complete one task at a time. If there are multiple tasks to be executed, they must queue up to be executed (the first task is completed, and then the next task is executed).

This mode is simple to implement, but it is bound to be inefficient as future requirements, transactions, and requests increase. Whenever one task takes a long time to execute, subsequent tasks cannot be executed in that time. A common browser non-response (suspended animation) is usually the result of a single piece of Javascript code running for so long (such as an infinite loop) that the entire page gets stuck in one place and no other task can be performed. (disadvantages)

To solve this problem, the JavaScript language divides task execution modes into synchronous and asynchronous:

Synchronous mode: it is a kind of execution mode mentioned above, the latter task waits for the end of the previous task, and then executes, the execution order of the program is consistent with the order of the task, synchronous.

Asynchronous mode: is each task has one or more of the callback function (the callback) to the previous after the task, not to perform a task, after but the callback function, after a task is before the end of a task before execution, so the program execution order the order is not consistent with the task, asynchronous.

Asynchronous mode “is very important. On the browser side, long operations should be performed asynchronously to prevent the browser from becoming unresponsive. The best example of this is Ajax operations. On the server side, “asynchronous mode” is even the only mode, because the execution environment is single-threaded, and if you allow all HTTP requests to be executed synchronously, the server performance deteriorates dramatically and quickly becomes unresponsive. (Importance of asynchronous mode)

Task execution order: ❤️ talk about js macro task and micro task! _ Paper Plane Blog -CSDN blog

Here are some front-end asynchronous solutions for your friends:

First, the traditional plan

1, callback function (callback)

The basic approach to asynchronous programming.

The first thing to note is that the callback function is just an implementation, not an asynchronous pattern-specific implementation. Callbacks can also be used in synchronous (blocking) scenarios and other scenarios.

The definition of the callback function:

Function A is passed as an argument (function reference) to another function B, and this function B executes function A. Let’s say function A is called the callback function. If there is no name (function expression), it is called an anonymous callback function.

Example: When you drop your girlfriend off at the end of a date, you’ll say, “Text me when you get home. I was worried about you.” And then your girlfriend actually texted you when she got home. This is actually a callback process. You leave a parameter function (asking your girlfriend to send you a message) to your girlfriend, and then your girlfriend goes home, and the return action is the main function. She has to get home, the main function is done, and then the function that’s passed in, and then you get a message.

Function A(callback) {callback(); Console. log(' I am the main function '); } function B(){setTimeout("console.log(' I am a callback ')", 3000); } // call the main function, pass function B into A(B); // Output result // I am the main function // I am the callback functionCopy the code

In the above code, we define the main function and the callback function, then call the main function and pass in the callback function.

When we define the main function, we let the code execute the callback() callback first, but the output is the content of the later output callback. This means that the main function doesn’t have to wait for the callback function to finish executing and can execute its own code. So callbacks are usually used for time-consuming operations. Such as Ajax requests, such as processing files, etc.

Advantages: Simple, easy to understand and deploy.

Cons: Unreadable and unmaintainable code, highly coupled parts, messy process, and only one callback per task.

2. Event monitoring

Adopt event-driven mode.

The execution of tasks depends not on the order of the code, but on whether an event occurs.

Listener functions include: on, bind, listen, addEventListener, observe, etc.

Take F1 and F2 for example. First, bind an event to F1 (written in jquery).

f1.on('done',f2); // Execute f2 when the done event occurs in f1.Copy the code

Then rewrite f1:

Function f1(){setTimeout (function(){f1.trigger('done'); }, 1000); }Copy the code

F1.trigger (‘done’) indicates that, immediately after execution, a done event is triggered to start execution of F2.

Advantages: Easy to understand, multiple events can be bound, each event can specify multiple callback functions, and can be decouple, which is good for modularity.

Disadvantages: The entire application becomes event-driven and the flow becomes unclear.

Typical event monitoring cases

(1). The onclick method:

Element.onclick = function(){// handler}Copy the code

Advantages: Compatible with mainstream browsers.

Disadvantages: When multiple events are bound to the same Element, only the last event is added.

Such as:

element.onclick = handler1;
element.onclick = handler2;
element.onclick = handler3;
Copy the code

Only Handler3 will be added above, so we use another method (attachEvent and addEvenListener) to add events.

AttachEvent and addEvenListener methods:

//IE:attachEvent ("onclick",handler1); elment.attachEvent("onclick",handler2); elment.attachEvent("onclick",handler3);Copy the code

The execution sequence of the above three methods is as follows: 3-1.

Elment. AddEvenListener ("click",handler1,false); elment.addEvenListener("click",handler2,false); elment.addEvenListener("click",handler3,false);Copy the code

The above execution sequence: 1-3.

PS: The third argument to this method is bubble fetch (useCapture), which is a Boolean value: false for insideout (event bubble), true for outside-in (event capture).

<div id="id1">
    <div id="id2"></div>
</div>
Copy the code
document.getElementById("id1").addEventListener("click",function(){ console.log('id1'); },false); document.getElementById("id2").addEventListener("click",function(){ console.log('id2'); },false); // Select div with id=id2 and print id2 in console. Id1 document.getelementById ("id1").adDeventListener ("click",function(){console.log('id1'); },false); document.getElementById("id2").addEventListener("click",function(){ console.log('id2'); },true); // Click the div with id=id2, and output first id1, then ID2 in consoleCopy the code

DOM methods addEventListener() and removeListenner() :

AddEventListenner () and removeListenner() represent functions used to assign and delete events. Both methods take three arguments: string (event name), function to fire the event, and specify the period or phase of the event handler (Boolean). See (2) for examples

(4). General time adding method:

On :function(elment,type,handler){return element.attachevent? elment.attachEvent("on"+type,handler):elment.addEventListener(type,handler,false); }Copy the code

Ii. Tool scheme

The tool scheme can be roughly divided into the following five:

  • Promise
  • Gengerator function
  • async await
  • In the node. Js nextTick setImmidate
  • Third-party library async.js

Here is a detailed description of each application:

1. Promise

The meaning and development of Promise

Meaning: The Promise object is used to represent the eventual completion (or failure) of an asynchronous operation and its resulting value. In simple terms, it is used to handle asynchronous operations, executing the successful operation if the asynchronous process succeeds, and catching errors or stopping subsequent operations if the asynchronous process fails.

Evolution: Promise is a solution to asynchronous programming that is more reasonable and powerful than traditional solutions (callback functions and event listeners). It was first proposed and implemented by the community. ES6 has written it into the language standard, unified syntax, and provided Promise natively.

Its general form:

new Promise( /* executor */ function(resolve, reject) { if (/* success */) { // ... Execute the code resolve(); } else { /* fail */ // ... Execute code reject(); }});Copy the code

The executor parameter in Promise is an executor function that takes resolve and reject. This is a pity. If the asynchronous operation succeeds, you can call resolve() to set the state of the instance to fulfilled. If it fails, you can call Reject () to set the state of the instance to rejected (failed).

We can regard the Promise object as an assembly line of a factory. For the assembly line, from the perspective of its work function, it has only three states, one is the initial state (when the machine is just started), one is the successful processing of the product, and the other is the failure of the processing of the product (some faults occur). There are also three states for a Promise object: pending: The initial state, also known as pending, which is the state after the executor function is called when the Promise is initialized. This is a big pity: the completion state, which means that the asynchronous operation will be successful.

  • Pending: The initial state, also known as pending state, is the state after the executor function is called when a Promise is initialized.
  • This is a big pity: the completion state, which means that the asynchronous operation will be successful.
  • Rejected: indicates the failed state. It indicates that the asynchronous operation fails.

There are only two states in which it can be converted, namely:

  • Operation success: Pending -> Depressing
  • Operation failed: Pending -> Rejected

Note: This state transformation is one-way and irreversible. The determined state (depressing/Rejected) cannot be reversed back to the initial state.

Methods for Promise objects (apis)

(1).Promise.prototype.then(callback)

The Promise object contains then methods. The then() call returns a Promise object, meaning that the instantiated Promise object can be chain-called, and that the THEN () method can accept two functions, one for handling success and one for handling error results.

As follows:

SetTimeout (function() {resolve('success'); var promise1 = new Promise(function(resolve, reject); }, 2000); }); promise1.then(function(data) { console.log(data); // success }, function(err) { console.log(err); }). Then (function(data) {console.log(' chain call: '+ data); Function (data) {//.... });Copy the code

Here we focus on the state of the Promise returned after the promise1. Then () call. Is it pending, depressing, or Rejected?

The state of the returned Promise object is based on the value returned by the promise1.then() method.

  1. If a parameter value is returned in the then() method, the returned Promise will become the received state.
  2. If an exception is thrown in the then() method, the returned Promise will be rejected.
  3. If the then() method calls the resolve() method, the Promise returned will become the received state.
  4. If the then() method calls the Reject () method, the returned Promise becomes a reject state.
  5. If the then() method returns a new instance of a Promise with an unknown state (pending), the returned Promise is an unknown state.
  6. If the then() method does not explicitly specify resolve(data)/reject(data)/return data, the new Promise returned is the receive state, which can be passed down layer by layer.

(2).Promise.prototype.catch(callback)

The catch() method, like the then() method, returns a new Promise object, which is mainly used to catch exceptions during asynchronous operations. Therefore, we usually omit the second argument to the then() method, passing control of error handling to the following catch() function, as follows:

var promise3 = new Promise(function(resolve, reject) { setTimeout(function() { reject('reject'); }, 2000); }); Promise. then(function(data) {console.log(' this is a big pity '); // this will not trigger //... }). Catch (function(err) {// The last catch() method catches console.log(' error: '+ err) on this Promise chain; Reject});Copy the code

(3).Promise.all()

Promise.all() takes an argument that must be iterable, such as an array.

It is usually used to handle concurrent asynchronous operations, that is, their results do not interfere with each other, but they need to be executed asynchronously. It ultimately has only two states: success or failure.

The task in. Then is executed after all tasks in the array have been executed

This is a big pity. Its state is affected by the states of each value in the parameter. That is, only when all the states inside are fulfilled, it will become a pity; otherwise, it will become rejected.

A successful call returns an array of ordered values, that is, the result of operating on the values of the array of arguments passed in.

As follows:

Const p1 = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(console.log('p1 task 1'))},1000)}). Then (data =>{ Console. log('p1 task 2')}).then(res =>{console.log('p1 task 3')}).catch(err =>{throw err}) const p2 = new Promise((resolve,reject)=>{resolve(console.log('p2 task 1'))}). Then (data =>{console.log(' P2 task 2')}). Catch (err =>{ Promise.all([p1,p2]). Then (()=>console.log('done'))Copy the code

(4).Promise.race()

Promise.race() is similar to promise.all () in that it receives an iterable parameter, but the difference is that the state of promise.race () is not entirely affected by the state within the parameter. Once the state within the parameter changes, Then the state of the Promise is the changed state. As the word race literally means, the fastest runner wins. As follows:

var p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 300, 'p1 doned'); }); var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 50, 'p2 doned'); }); var p3 = new Promise(function(resolve, reject) { setTimeout(reject, 100, 'p3 rejected'); }); This will be a big pity. Race ([p1, P2, p3]). Then (function(data) {// This will be a big pity. The status changes to Rejected console.log(data); // p2 doned }).catch(function(err) { console.log(err); });Copy the code

(5).Promise.resolve()

Promise.resolve() accepts a parameter value, which can be a generic value, an object with a then() method, and a Promise instance. Normally, it returns a Promise object, which is fulfilled. However, if an error occurs during parsing, the returned Promise object will be set to the Rejected state. As follows:

Var p4 = promise.resolve (5); p4.then(function(data) { console.log(data); / / 5}); Var obj = {then: function() {console.log(' then in obj '); }}; var p5 = Promise.resolve(obj); P5. then(function(data) {console.log(data); // then()}); Var p6 = promise.resolve (7); var p7 = Promise.resolve(p6); P7.then (function(data) {console.log(data); / / 7}); Var p8 = promise.reject (8); // Reject = promise.reject (8); var p9 = Promise.resolve(p8); P9. Then (function(data) {console.log(' depressing :'+ data); }). Catch (function(err) {console.log('rejected:' + err); // rejected: 8 });Copy the code

(6).Promise.reject()

Promise.reject() is the opposite of promise.resolve (), which accepts a parameter value, Reason, which is the reason for the exception. The returned Promise object will be set to the Rejected state. As follows:

Var p10 = promise.reject (' reject '); p10.then(function(data) { console.log(data); }). Catch (function(err) {console.log(err); Function (data) {console.log(' status: pity '); // state: depressing});Copy the code

In short, unless the promise.then () method throws an exception internally or explicitly sets it to the Rejected state, the Promise state it returns will be a big fulfilled state, and its state will not be affected by the state at the next level.

2. Gengerator function

Another common solution for asynchronous programming is the Generator function. As the name implies, it is a generator, which is also a state machine. It has values and related states inside. The generator returns an Iterator object, through which we can manually traverse the related values and states to ensure the correct execution order.

Generator functions provided by ES6.

Three things in general:

  1. Add one after the function keywordThis function is called a generator function
  2. * The function body has the yield keyword, followed by each task, or it can have the return keyword, which preserves a single data
  3. * Next function call, several calls, that is, several human task execution

Simple to use

Generator is declared like a normal function declaration, with the addition of *****, and you will normally see the yield keyword inside the function.

function* showWords() {
    yield 'one';
    yield 'two';
    return 'three';
}

var show = showWords();

show.next() // {done: false, value: "one"}
show.next() // {done: false, value: "two"}
show.next() // {done: true, value: "three"}
show.next() // {value: underfined, done: true}
Copy the code

The above code defines a generator function called showWords that returns an iterator object (show).

After the next method is called, the first yield statement is executed within the function, which outputs the current state done (whether the iterator is traversed) and the corresponding value (typically the result of the operation following the yield keyword).

Each time next is called, a yield statement is executed and paused at that point. When the return is complete, the generator function exits, and if there are any further yield operations, it will not be executed.

Of course, there are cases where :(next() is less than yield)

Function * g1(){const g1done = g1() console.log(g1done.next()) //{function* g1(){yield 'task 1' 2' yield' task 3' return 'task 4'} const g1done = g1() console.log(g1done. Value: 'task 1', done: false} console.log(g1done.next()) //{value:' task 2', done: false}Copy the code

Plus yield and yield star

Sometimes we’ll see that yield is followed by an asterisk, what is it, and what does it do?

Similar to the asterisk before generators, the asterisk after yield is also related to generators, for example:

function* showWords() {
    yield 'one';
    yield showNumbers();
    return 'three';
}

function* showNumbers() {
    yield 10 + 1;
    yield 12;
}

var show = showWords();
show.next() // {done: false, value: "one"}
show.next() // {done: false, value: showNumbers}
show.next() // {done: true, value: "three"}
show.next() // {done: true, value: undefined}
Copy the code

Add a generator function that we want to call once in showWords and simply yield showNumbers() does not execute yield 10+1 in the function.

Because yield only returns the right-hand value, showNumbers() is not a normal function call. It returns an iterator.

So change yield* to let it automatically iterate through the object:

function* showWords() {
    yield 'one';
    yield* showNumbers();
    return 'three';
}

function* showNumbers() {
    yield 10 + 1;
    yield 12;
}

var show = showWords();
show.next() // {done: false, value: "one"}
show.next() // {done: false, value: 11}
show.next() // {done: false, value: 12}
show.next() // {done: true, value: "three"}
Copy the code

Note that both yield and yield* can only be used within generator functions, and will generate an error if used within normal functions.

function showWords() {
    yield 'one'; // Uncaught SyntaxError: Unexpected string
}
Copy the code

Yield * does not return an error directly, but it is problematic because there is no Iterator interface in the ‘one’ string, and no yield provides traversal:

function showWords() {
    yield* 'one'; 
}

var show = showWords();

show.next() // Uncaught ReferenceError: yield is not defined
Copy the code

In crawler development, we often need to request multiple addresses. To ensure order, introduce a Promise object and a Generator function. Look at this simple example:

var urls = ['url1', 'url2', 'url3'];

function* request(urls) {
    urls.forEach(function(url) {
        yield req(url);
    });

//     for (var i = 0, j = urls.length; i &lt; j; ++i) {
//         yield req(urls[i]);
//     }
}

var r = request(urls);
r.next();

function req(url) {
    var p = new Promise(function(resolve, reject) {
        $.get(url, function(rs) {
            resolve(rs);
        });
    });

    p.then(function() {
        r.next();
    }).catch(function() {

    });
}
Copy the code

In the code above, forEach iterates through an array of urls. Instead of using the yield keyword inside anonymous functions, use the for loop in the comment instead.

Passing arguments in the next() call

Parameter values can be injected to alter the return value of the last yield, for example:

function* showNumbers() {
    var one = yield 1;
    var two = yield 2 * one;
    yield 3 * two;
}

var show = showNumbers();

show.next().value // 1
show.next().value // NaN
show.next(2).value // 6
Copy the code

The first call to next returns one as 1, but the second call to next returns one as undefined because the generator does not automatically store the value of the variable, and we need to specify this manually. In this case, the value of two is NaN. On the third call to next, yield 3 * two is executed and the last yield return value two is set to 2 by passing the parameter.

Another chestnut:

Since Ajax requests involve networks and are difficult to handle, setTimeout is used to simulate the return of Ajax requests, in order, and pass the data returned each time:

var urls = ['url1', 'url2', 'url3'];

function* request(urls) {
    var data;

    for (var i = 0, j = urls.length; i &lt; j; ++i) {
        data = yield req(urls[i], data);
    }
}

var r = request(urls);
r.next();

function log(url, data, cb) {
    setTimeout(function() {
        cb(url);
    }, 1000);
    
}

function req(url, data) {
    var p = new Promise(function(resolve, reject) {
        log(url, data, function(rs) {
            if (!rs) {
                reject();
            } else {
                resolve(rs);
            }
        });
    });

    p.then(function(data) {
        console.log(data);
        r.next(data);
    }).catch(function() {
        
    });
}
Copy the code

R.ext () has no arguments, and then r.ext (data) passes in data.

Note line 16 of this code, where the url variable is used for the parameter to be compared with the data.

Since next() initially had no arguments, if you had simply changed the URL to data, you would have judged the promise object’s data! Rs == undefined, reject.

So swap lines 16 for cb (data | | url).

The first log output is url = ‘urL1’, then data = ‘urL1’ is passed to the REQ request, and data = ‘urL1’ is output in the log.

for… Of loop instead of.next()

In addition to iterating over an iterator object using the.next() method, the new loop provided by ES6 for… Of can also be traversed, but unlike next, it ignores the value returned by return, such as:

function* showNumbers() {
    yield 1;
    yield 2;
    return 3;
}

var show = showNumbers();

for (var n of show) {
    console.log(n) // 1 2
}
Copy the code

Besides, deal with for… The of loop, with methods that call iterator interfaces, can also iterate over generator functions, such as extension operators… The use of:

function* showNumbers() {
    yield 1;
    yield 2;
    return 3;
}

var show = showNumbers();

[...show] // [1, 2, length: 2]
Copy the code

For more information, see MDN-Generator.

3, async await (emphasis)

New async function in ES7.

To work more comfortably with promises, it’s called async/await, and it’s very easy to understand and use.

Format and knowledge

Async function aa(){await 'task 1' await' task 2'}Copy the code

async:

Let’s start with the async keyword, which is placed in front of a function. Like this:

Async function timeout() {return 'hello world'; }Copy the code

The async word in front of the function implies a simple thing: the function always returns a promise, and if there is a return < non-promise > statement in the code, JavaScript will automatically wrap the returned value as the Promise resolved value.

For example, the code above returns a promise with an Resolved value of 1, which we can test

Async function f() {return 1} f(). Then (alertCopy the code

We can also explicitly return a promise, which will have the same result:

Async function f() {return promise.resolve (1)} f().then(alertCopy the code

So async ensures that the function returns a promise, even if it contains non-promises, without requiring you to write a cumbersome promise. Simple enough, right? But more than that, there is another keyword await, which can only be used in async functions, which is also cool.

await:

// Use let value = await promise only inside async functionsCopy the code

The keyword await makes JavaScript wait until a promise executes and returns its result.

Here is an example of a promise resolve after 1s:

async function f() { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve('done! '), 1000)}) let result = await promise // Until promise returns a resolve value (*) alert(result) // 'done! ' } f()Copy the code

The function ‘waits’ on the await line and resumes when the promise is finished. Resolve is the final result, so the code above prints ‘done! ‘

We emphasize that await literally makes JavaScript wait until the promise processing completes,

And then continue with the results. This does not cost any CPU resources because the engine can do other things at the same time: execute other scripts, handle events, and so on.

This is just a more elegant way to get the promise value, and it’s easier to read and write than a promise.

Note no: you can use await in regular functions

If we try to use await in a non-async function, we get a syntax error:

function f() {
   let promise = Promise.resolve(1)
   let result = await promise // syntax error
}
//Uncaught SyntaxError: await is only valid in async function
Copy the code

If we forget to place async before the function, we get an error like this. As mentioned above, await can only work in async functions.

We can’t see the use of async/await in the previous cases. What if we want to count 3 numbers and output the result?

async function testResult() {
    let first = await doubleAfter2seconds(30);
    let second = await doubleAfter2seconds(50);
    let third = await doubleAfter2seconds(30);
    console.log(first + second + third);
}
Copy the code

After 6 seconds, the console outputs 220, and we can see that writing asynchronous code is just like writing synchronous code; there is no callback region anymore.

Here’s another one: Let’s start with a question

ReadFile (‘./01- promise.js ‘) results in a Promise, but with async await it results in concrete data?

Fs module is a file module that can manipulate files. ReadFile () is a file module that can read files

Const fs = require('fs')// import fs module const readFile = (filename) =>{return new Promise((resolve,reject)=>{ fs.readFile(filename,(err,data)=>{ resolve(data.toString()) }) }) } const asyncFn = async() => { //const f0 = EadFile ('. / 01 - Promise. Js') / / similar {value: 'the file content, done: False} const f1 = await readFile('./ 01-promise.js ').then(data=>data) Const f2 = await readFile('./02-generator.js') // File contents console.log(f1) console.log(f2)} asyncFn()Copy the code

ReadFile () defines a Promise method to read the file. There’s a pit where we’re now returning data. There are three layers of functions, so if you don’t use the New Promise method, you can see if you can return data using normal methods.

AsyncFn () prints the contents of the file, and the line const f1 = eadFile(‘./ 01-promise.js ‘) prints a Promise{‘ contents of the file ‘}, similar to the {value that the generator printed earlier: ”, done: False}, only omit done, we know, we read the file, must be the contents of the file, if output Promise{‘ file content ‘}, we will not be able to retrieve the content, but await very good to solve this problem, before adding “await” directly output the file content.

So: this question can be summed up in a small way

  1. Async uses generator sugar and generates {value: “,done:false} await to extract value directly
  2. With Promise + async, we can return data from a nested (asynchronously executed) inner function

Summary about async/await

Async in front of a function does two things:

Making the function always return a promise, allowing the await keyword in front of an await promise causes JavaScript to wait until the promise processing is complete. And then:

If it is an error, the exception is raised, just as throw Error was called there. Otherwise, it will return a result, which we can assign to a value and together they provide a nice framework for writing asynchronous code that’s easy to read and write.

With async/await, we rarely need to write promises.then /catch, but we should still not forget that they are based on promises, because sometimes (for example in the outermost scope) we have to use these methods. Promise.all is also a great thing to wait for many tasks at once.

Node.js nextTick setImmidate

nextTick vs setImmediate

(1). What is polling

Nodejs is event-driven. There is a loop thread that takes the task execution or I/O operation from the event queue and transfers it to the background thread pool. Each execution of this loop thread is considered as a polling process.

(2).setimmediate () uses the instant timer to perform its work immediately, which is executed after the event poll and is called one at a time to prevent the poll from blocking.

Details: Window. SetImmediate () – Web APIs | MDN

(3). The Process. NextTick () is used

Unlike setImmediate(), which executes before the event poll, there is a default process.maxtickdepth =1000 to limit the number of nextTick() events that can be executed per loop in the event queue in order to prevent I/O starvation.

Details: the process process | Node. Js API documentation

Conclusion:

  1. The nextTick() callback executes with higher precedence than setImmediate().
  2. Process.nexttick () belongs to idle observers, and setImmediate() belongs to check observers. In each cycle check, the IDLE observer precedes the I/O observer, and the I/O observer precedes the Check observer.
  3. In a concrete implementation, the callbacks of process.Nexttick () are stored in an array, and the result of setImmediate() is stored in a linked list.
  4. Behaviourally, process.nexttick () executes all the callbacks in the array in each loop, while setImmediate() executes one of the linked list’s callbacks in each loop.

5. Third-party library Async.js

Async.js is a third-party library with many apis.

Exposes an async object that has a number of apis (multitasking), such as Parallel, series, etc.

// Unlike series/ Waterfall, tasks are executed side-by-side, and callback does not execute the next task. Async. Parallel ([function(callback){callback(null,' callback ')}, function(callback){callback(null,' callback ')}, ],(err,data)=>{ console.log('data',data) })Copy the code
Async. Series ([function(callback){// do some stuff... callback(null, 'one');  }, function(callback){ // do some more stuff ... callback(null, 'two');  } ], // optional callback function(err, results){ // results is now equal to ['one', 'two'] });Copy the code

Async. Js: async-js-npm