What is asynchronous?
The so-called asynchronous, is simply asynchronous tasks (not immediately complete tasks); But js will not wait for you to complete this task, but directly execute the following task; Wait until you’ve completed the tasks above to implement the logic. For example, js reads a file is an asynchronous process.
The syntactic goal of asynchronous programming is how do you make it more like synchronous programming
1. Callback function
Scenario: Read a file
let fs = require('fs')
fs.readFile('./1.txt'.'utf8'.function(err, data){// The characteristic of the callback is that the first argument is usually the error objectif(err) {console.log(err)}elseData console.log(data)}})Copy the code
Of course, callbacks have their drawbacks:
- Unable to catch error (using try catch)
funnction readFile (fileName) {
fs.readFile(fileName, 'utf8'.function (data) {
if (err) {
console.log(err)
} else {
console.log(data)
}
})
}
try {
readFile('./1.txt'} catch (e) {// if there is an error reading the file, the error message console.log('err', e)
}
Copy the code
- Can’t return
// readFile method cannot return the contents of the File read (data)Copy the code
- Callback to hell; For example, request a page list, the general server to read at least two files, template files and data; This leads to the nesting problem
fs.readFile('./template.txt'.'utf8'.function (err, template) {
fs.readFile('./data.txt'.'utf8'.function(err, data) {console.log(template, data)})}) // This code is called the devil pyramid; // 1, the code is ugly // 2, difficult to maintain // 3, inefficient because they are serial; Only one file can be requested at a timeCopy the code
2. Event publish subscribe (to solve the problem of nested callbacks)
let EventEmitter = require('events') // nodejs is one of the core modules; There are two core methods: on >> means to register to listen to emit >> means to emit eventslet eve = new EventEmitter()
letHTML = {} // Store the page template and data eve.on('onloading'.function (key, value) {
html[key] = value
if (Object.keys(html).length == 2) {
console.log(html)
}
})
fs.readFile('./template.txt'.'utf8'.function (err, template) {
eve.emit('onloading', template) // Triggers an onLoading event and executes the event's callback function to fill in the template in HTML}) fs.readfile ('./data.txt'.'utf8'.function (err, template) {
eve.emit('onloading', template) // Triggers an onloading event and executes the event's callback function to fill in the HTML})Copy the code
3. The Sentinel variable (which also handles callback nesting) has already solved the problem of callback nesting, but the events module needs to be introduced. Using the Sentinel variable can also solve the problem of callback nesting without the need to introduce other modules
// Define a sentinel function to handle thisfunction done (key, value) {
html[key] = value
if (Object.keys(html).length == 2) {
console.log(html)
}
}
fs.readFile('./template.txt'.'utf8'.function (err, template) {
done('template', template)
})
fs.readFile('./data.txt'.'utf8'.function (err, template) {
done('data', data)}) // You can encapsulate a higher-order function to generate the sentry functionfunction render (length, cb) {
let htm = {}
return function (key, value) {
html[key] = value
if (Object.keys(html).length == length) {
cb(html)
}
}
}
let done = render(2, function (html) {
console.log(html)
})
Copy the code
All of the above methods use callbacks to handle asynchrony; Our goal is to move from asynchronous to synchronous
let promise1 = new Promise(function (resolve, reject) {
fs.readFile('./1.txt'.'utf8'.function (err, data) {
resolve(data)
})
})
promise1
.then(function (data) {
console.log(data)
})
Copy the code
Promise
When we call a function, it does not execute immediately. Instead, we need to iterate manually (next method); In simple terms, a call to a generator function returns an iterator. You can use an iterator to iterate over each breakpoint (yield). A call to the next method returns a value, which is the output of the generator function; The next method can also take arguments, which are data input into the generator function
- Simple use of generator
// A method name preceded by * is a generator functionfunction *foo () {
var index = 0;
while(index < 2) { yield index++; }} var bar = foo(); // Return an iterator console.log(bar.next()); // { value: 0,done: false }
console.log(bar.next()); // { value: 1, done: false }
console.log(bar.next()); // { value: undefined, done: true }
Copy the code
- Generator + Promise addresses asynchronous implementation
function readFile (filaName) {
return new Promise(function (resolve, reject) {
fs.readFile(filename, function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
}
function *read() {
let template = yield readFile('./template.txt')
let data = yield readFile('./data.txt')
return{template: template, data: data}let r1 = read(a)let templatePromise = r1.next().value
templatePromise.then(function(template) {// Pass the contents of the obtained template to the generator functionlet dataPromsie = r1.next(template).value
dataPromise.then(function(data) {// Pass in the value of data the last time next is executed; Finally, return {template, data}let result = r1.next(data).value
console.log(result)
})
})
Copy the code
The implementation of generator + Promise already has some synchronization in it; With a few tools (CO), you can gracefully write the above code
// Implement the co method // the argument is a generator functionfunction co (genFn) {
let r1 = genFn()
return new Promise(function(resolev, reject) {
!function next(lastVal) {
let p1 = r1.next(lastVal)
if (p1.done) {
resolve(p1.value)
} else{p1.value.then(next, reject)}}()})}read).then(function(result) {
console.log(result)
})
Copy the code
Async is a syntactic sugar that encapsulates Generator functions and automatic actuators (CO) in a single function
async function read() {
let template = await readFile('./template.txt');
let data = await readFile('./data.txt');
return template + '+'+ data; } // is equivalent tofunction read() {return co(function* () {let template = yield readFile('./template.txt');
let data = yield readFile('./data.txt');
return template + '+' + data;
});
}
Copy the code
Conclusion: The goal of asynchronous programming development is to make asynchronous logic code look synchronous; Develop Async/await; Is a milestone in the exploration of handling asynchronous programming.