basic concept
The forms of traditional JavaScript asynchronous programming are roughly divided into the following categories.
- Callback
- Event monitoring
- Publish/Subscribe
- Promise object
asynchronous
The continuous execution of a task is called synchronization. If the task is executed in two steps, after the first step is executed, other tasks are executed, and when you are ready, the second step is executed again. This kind of discontinuous execution is called asynchronous.
Callback
The callback function is to write the task executed in the second step separately in a function, and call this function directly when the task is re-executed. The English name of the callback function is callback
, and the literal translation is "recall".
loadData(url, function (data) {
console.log(data);
});
Note: After the first step of the task is executed, the context of the task is over, so we generally use var that = this
this
point when the first step is executed, so that it can be used in callbacks.
function Api(url) {
this.url = url;
this.request = function () {
var that = this
setTimeout(function () {
console.log('url', that.url)
}, 1000)
}
}
var api = new Api('http://127.0.0.1')
api.request() // url http://127.0.0.1
Generator function
In the asynchronous programming solution, ES6 also provides the Generator function. It is actually an ordinary function with unique characteristics
- There is an asterisk between
function
yield
is used inside the function body to define different internal states.
function* statusGenerator() {
yield 'pending';
yield 'running';
return 'end';
}
var st = statusGenerator();
The above code statusGenerator
function returns an iterator object. Three states are defined in the function. Call the iterator next
method to point to the next state.
st.next() // { value: 'pending', done: false }
st.next() // { value: 'running', done: false }
st.next() // { value: 'end', done: false }
yield expression
yield
expression is the pause flag. When the iterator executes next
.
- When the
yield
expression is encountered, the execution of the following operations is suspended, and the value of the expression afteryield
value
attribute value of the returned object. - The next time the
next
method is called, the execution will continue until the nextyield
expression is encountered. - If no new
yield
expression is encountered, it will run until the end of the function until thereturn
statement, andreturn
the value of the expression after thevalue
attribute value of the returned object. - If the function does not have the
return
statement, thevalue
attribute value ofundefined
.
for...of loop
We can also use for...of
to traverse.
function* statusGenerator() {
yield 'pending';
yield 'running';
return 'end';
}
var st = statusGenerator();
for(let v of st){
console.log(v)// pending running
}
Generator application
Coroutine
coroutine means that multiple threads cooperate with each other to complete asynchronous tasks. It is an asynchronous programming solution for some programming languages, such as the coroutine implementation goroutine
. The general flow of the co-program execution is as follows:
- The coroutine
A
starts to execute. - The
A
halfway through, enters a pause, and the execution right is transferred to the coroutineB
. - (After a period of time)
B
right of execution. - The coroutine
A
resumes execution.
The coroutine in JavaScript implements the Generator
function, which can hand over the execution right of the function (that is, suspend execution) at the specified place ( yield
For example: we implement a countdown function, wait for the countdown after the task is ready, and execute it together.
function* countdown(num, running) {
do {
yield num--
} while (num > 0)
running()
}
const tasks = []
const ct = countdown(3, function () {
console.log('start run task')
for (let task of tasks) {
task()
}
})
for (let i = 0; i < 3; i++) {
tasks.push(function () {
console.log('task '+ i)
})
ct.next()
}
ct.next()
An asynchronous request package
var fetch = require('node-fetch');
function* request(){
var url = 'xxxx';
var user = yield fetch(url); // 返回promise对象,data: {'user':'xxxx'}
console.log(user);
}
var req = request();
var result = req.next();
result.value.then(function(data){
return data.user
}).then(function(user){
req.next(user); // 将 user信息传到 request()函数,被user变量接收。
});
async function
ES2017 introduced the async
and await
keywords. Using these keywords, you can write Promise
in a more concise way, without the need to chain call promise
deliberately.
The function declared by async
async
function. You can think of async as the syntactic sugar of Generator, because they have the same essence.
Generator writing
const loadData = function (url) {
return new Promise(function (resolve, reject) {
resolve(data);
});
};
const request = function* () {
const user = yield loadData('https://user');
const goods = yield loadData('https://goods');
console.log(user, goods);
};
async writing
const loadData = function (url) {
return new Promise(function (resolve, reject) {
resolve(data);
});
};
const request = async function () {
const user = await loadData('https://user');
const goods = await loadData('https://goods');
console.log(user, goods);
};
Basic usage
async
function returns a Promise object. When the function is executed, once it encounters await
it will return first, wait until the asynchronous operation is completed, and then execute the following statement in the function body.
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello', 50);
The value returned by the return
statement inside the async
function will become the parameter of the callback function of the then
async function hello() {
return 'hello';
}
hello().then(v => console.log(v))
// "hello"
async
function throws an error internally, which will cause the returned Promise object to change to the reject
state. The thrown error object will be received by the callback function of the catch
async function hello() {
throw new Error('Error');
}
hello().then(
v => console.log(v),
e => console.log( e)
) // //Error: Error
await command
Under normal circumstances, await
followed by a Promise object, and the result of the object is returned. If it is not a Promise object, the corresponding value is returned directly.
async function hello() {
return await 'hello'
}
hello().then(v => console.log(v)) // hello
async function hello() {
return await Promise.resolve('hello');
}
hello().then(v => console.log(v)) // hello
Error handling
If await
is an error in the asynchronous operation following 06179232d4e461, then the Promise object returned by the function async
reject
.
async function hello() {
await new Promise(function (resolve, reject) {
throw new Error('error');
});
}
hello()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:error
So it is best to put the await
command in the try...catch
code block.
async function hello() {
try {
await new Promise(function (resolve, reject) {
throw new Error('error');
});
} catch(e) {
console.log('err:', e) // error
}
return await('hello');
}
const h = hello();
h.then((v) => {console.log(v)}) // hello
summary
This article records some ways in JavaScript asynchronous programming, Generator
function and async
and await
syntax, welcome to leave a message and exchange.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。