Call back to hell and Promise solutions

I. Preface:

In this case, I will introduce the basic concept and application of the callback function, and step by step to demonstrate how the callback hell is generated, and finally how to solve the problem of callback hell

How is the callback function created

First I have a requirement here: print the variable STR

function getDate(){
	function processData(){
		var str="hello world"; }}Copy the code

A normal mind might print like this

function getDate(){
	function processData(){
		var str="hello world";
		return str;
	}
	processData();
}
var res=getDate();
console.log(res);//undefined
Copy the code

But the actual result is undefined. Why is that?

There’s a concept involved here: asynchrony

What is asynchrony?

Do two things at the same time. For example, do your homework while listening to music

Since there are two things going on at the same time, it is inevitable that:

  • The end time of each, which may or may not be the same
  • The result of each end

Ok, why can’t the above example print STR?

GetDate () and processData() are two different functions, just nested together. Whether they end at the same time or not, console.log(res) prints the return value of getDate(), but getDate() does not return a value, so the result is U ndefined

So what’s the solution? Easy

Give getData() a return value

function getDate(){
	function processData(){
		var str="hello world";
		return str;
	}
	return processData();
}
var res=getDate();
console.log(res);//hello world
Copy the code

At this point, we have implemented printing the value of STR, but if we want to get the result of asynchronous function execution, is return the first priority?

In the following example, my requirement is to print the result of the add() execution

function add(x, y) {
    console.log(1)
    var res=setTimeout(function () {
        console.log(2);
      var result = x + y;
      return  result;
    }, 1000)
    
    console.log(3);
    return res;
}
console.log(add(20.30));
/ / the result
1
//
3
//
1
//
2
Copy the code

Are you surprised to see that printing add(20,30) results in 1 instead of 50?

So how does the above result come from, and how does the above code actually execute?

The first thing to make clear is that I want to print the result of add(20,30), which is the function’s return value, res

When the function add(20,30) is executed, the code is executed first

console.log(1)

Then perform

console.log(3)

Then perform

The console. The log (add (20, 30))

Then perform

The code inside the timer… console.log(2)…

Why is it in this order, and I will write another article about it in detail later

Given that the timer is an asynchronous operation, you might think that if you return the result of the asynchronous function “result” and assign it to “res”, then you would get the result of “add(20,30)”, but you don’t. Why?

Because res is actually the ID of a setTimeout recorded by the system, which can be used to cancel the timer in the future. What’s the problem? Where are the results of the anonymous function in the timer returned?

No variable receives the result returned by the timer anonymous function, nor can it

At this point, obviously we can’t print the result res of add(20,30)

And with that, it’s time to introduce our hero

Requirements like the above two examples are often encountered in real development, so we need to explore an effective solution, that is: callback function

What is a callback function

A callback function is a function passed as an argument to another function

Just like closures, there is no unique explanation for the concept of a callback function, but the closest we can come to understanding it in practice is simply that a callback function is an argument to a function

Basic model of callback function

There is no fixed way to write the basic model of the callback function. To write an heuristic model, use the simple example above: Print sum

function getDate(callback){
	function processData(){
        var sum=0;
		for(var i=0; i<4; i++){ sum++; } callback(sum);// Call the external function to carry out the internal value of the external access
    }	
    processData();
}
getDate((data) = >{
    console.log(data);
});
Copy the code

5. The application of callback function

In general, the purpose of taking a function as an argument is to get the result of an asynchronous operation inside the function

Six. How does the callback region come into being

I created three new files in the same directory:

aa.txt

bb.txt

cc.txt

test.js

TXT,bb. TXT,cc. TXT are aAAA, BBBB, CCCC respectively

Here is a test. Js

let path=require("path");
let fs=require('fs');
fs.readFile(path.join(__dirname,"./aa.txt"),"utf8".function(err,data){
	if(err) throw err
	console.log(data)
})
Copy the code

Execute the code and get aAAA

Now modify the code to print using a callback function

let path=require("path");
let fs=require('fs');

function getFileByPath(fpath,callback){
	fs.readFile(fpath,"utf8".function(err,data){
		if(err) return callback(err.message)
		callback(data)
	})
}

strurl=path.join(__dirname,"./aa.txt");
 getFileByPath(strurl,(data)=>{
	 console.log(data);
 })
Copy the code

Execute the code and get aAAA

Since err and data are printed above and share the same callback, for the sake of clear hierarchy of the code, use the callback function for them respectively, and modify the code below

function getFileByPath(fpath,succb,errcb){
	fs.readFile(fpath,'utf8',(err,data)=>{
		if(err) return errcb(err.message)
		succb(data)
	})
}
getFileByPath(path.join(__dirname,'aa.txt'),(data)=>{
	console.log(data)
},
(err)=>{
	console.log(err)
})
Copy the code

Execute the code and get aAAA

TXT,bb. TXT,cc. TXT

fs.readFile(path.join(__dirname,"aa.txt"),"utf8".function(err,data){
	console.log(data)
})

fs.readFile(path.join(__dirname,"bb.txt"),"utf8".function(err,data){
	console.log(data)
})
fs.readFile(path.join(__dirname,"cc.txt"),"utf8".function(err,data){
	console.log(data)
})
Copy the code

Repeat the code and observe the results

This problem is also caused by asynchrony, because the end times of the three file-reading functions are not necessarily the same

So people adopt this scheme to solve the problem

fs.readFile(path.join(__dirname,"aa.txt"),"utf8".function(err,data){
    console.log(data)
    fs.readFile(path.join(__dirname,"bb.txt"),"utf8".function(err,data){
        console.log(data)
        fs.readFile(path.join(__dirname,"cc.txt"),"utf8".function(err,data){
            console.log(data)  
        })  
    }) 
})
Copy the code

This structure ensures that functions are executed in the right order, but if we’re reading a lot of files, shouldn’t we just keep nesting them?

This is the geography of the pullback

Seven. The shortcomings of the writing method of callback region

  • Code hierarchy is not clear enough, the visual look is not good
  • If one of the nested codes fails, the following is not executed, fatal flaw

Solve callback hell

To address the drawbacks of writing callback hell, use the Promise solution

Let’s use Promise to read individual files

let p=new Promise(function(res,rej){
	fs.readFile(path.join(__dirname,'aa.txt'),'utf8'.function(err,data){
		if(err) rej(err.message)
		else res(data)
	})
})
p.then((data) = >{
	console.log(data)//aaaa
})
Copy the code

TXT,bb. TXT,cc. TXT file contents read out in turn

function fn(fpath){
  return new Promise(function(res,rej){
    fs.readFile(fpath,"utf8".function(err,data){
        res(data)
    })
  })
}

fn(path.join(__dirname,"aa.txt"))
.then((data) = >{
    console.log(data)
    return fn(path.join(__dirname,"bb.txt"))
})
.then((data) = >{
    console.log(data)
    return fn(path.join(__dirname,"cc.txt"))
})
.then((data) = >{
    console.log(data)
})
Copy the code

Nine. What is Promise

Special statement

The following content is referenced or quoted from:

Zhihu Future Technology column -ES6 Promise

Ruan Yifeng – Getting started with ECMAScript 6

1. The meaning of Promise

Promises are a solution to asynchronous programming. A Promise is simply a container that holds the result of some event that will end in the future, usually an asynchronous operation. Syntactically, a Promise is an object that is a constructor. From it you can get messages for asynchronous operations.

// The following code can be run directly from the browser console (Chrome)
> typeof Promise
"function" // This is a constructor
> Promise
function Promise() { [native code] } // ES6 native support
Copy the code

2. The characteristics of the Promise

(1) The state of the object is not affected by the outside world. The Promise object represents an asynchronous operation with three states: Pending, fulfilled and Rejected. Only the result of an asynchronous operation can determine the current state, and no other operation can change the state. That’s where the name “Promise” comes from. Its English name means “Promise,” indicating that nothing else can change it.

(2) Once the state changes, it will never change again, and this result can be obtained at any time. There are only two possibilities for the state of the Promise object to change from pending to depressing and from pending to Rejected. As long as these two things are happening the state is fixed, it’s not going to change, it’s going to stay the same and that’s called resolved. If the change has already occurred, you can add a callback to the Promise object and get the same result immediately. This is quite different from an Event, which has the characteristic that if you miss it and listen again, you will not get the result.

Note that in order to facilitate the writing, the “resolved” in this chapter only refers to the regrettable state, excluding the rejected state. With the Promise object, asynchronous operations can be expressed as a “synchronous operation” flow, avoiding layers of nested callback functions. In addition, Promise objects provide a unified interface that makes it easier to control asynchronous operations.

3. Promise instantiation

const promise = new Promise(function(resolve, reject) {
  // ... some code
  
  if (/* Asynchronous operation succeeded */){
    resolve(value);
  } else{ reject(error); }});Copy the code

The Promise constructor takes a function as an argument, resolve and reject. They are two functions that are provided by the JavaScript engine and do not need to be deployed themselves.

The resolve function changes the state of the Promise object from “unfinished” to “successful.” It will be called when the asynchronous operation succeeds and will pass the result of the asynchronous operation as an argument. The Reject function changes the state of the Promise object from “unfinished” to “failed” (i.e., from Pending to Rejected). It is called when the asynchronous operation fails and passes the error reported by the asynchronous operation as a parameter.

After the Promise instance is generated, you can use the THEN method to specify the resolved and Rejected state callback functions, respectively.

Note: Understanding these state changes can be understood in conjunction with the concept of a life cycle

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});
Copy the code

The then method can take two callback functions as arguments. The first callback is called when the Promise object’s state changes to Resolved. The second callback is called when the Promise object’s state changes to Rejected. The second function is optional and does not have to be provided. Both of these functions accept as arguments a value passed from the Promise object.

Well, I here for Promise related knowledge introduction so much,Promise more knowledge can go to the above I gave the two reference links for learning

3. Promise.then()methods

Once a Promise object is created, we can use the THEN method to make chained calls, and we can return each result to the next THEN method, which then processes the value. Each THEN method can create a new Promise object again, which is then returned to the next THEN method.

Now, let’s go back to how do we apply Promise to solve the callback problem?

let p=new Promise(function(res,rej){
	fs.readFile(path.join(__dirname,'aa.txt'),'utf8'.function(err,data){
		if(err) rej(err.message)
		else res(data)
	})
})
p.then((data) = >{
	console.log(data)//aaaa
})
Copy the code
  • When the instantiated object P is generated, the Promise constructor passes in a function that takes two arguments, res and rej

  • Function inside do an asynchronous action, read file aa.txt

  • If the read fails,rej(err.message) passes the result of the asynchronous action failure as a parameter

  • Otherwise, res(data) passes the success result of the asynchronous action as a parameter

TXT,bb. TXT,cc. TXT file contents read out in turn

function fn(fpath){
  return new Promise(function(res,rej){
    fs.readFile(fpath,"utf8".function(err,data){
        res(data)
    })
  })
}

fn(path.join(__dirname,"aa.txt"))
.then((data) = >{
    console.log(data)
    return fn(path.join(__dirname,"bb.txt"))
})
.then((data) = >{
    console.log(data)
    return fn(path.join(__dirname,"cc.txt"))
})
.then((data) = >{
    console.log(data)
})
Copy the code
  • Direct callfn(), and pass in parameters to perform the asynchronous action, returnpromiseInstance,
  • with.then()The callback function receives the value from the previous step and returns a new action
  • And so on until the last step