Home > Article > Web Front-end > Detailed explanation of how to use async function in js
This time I will bring you a detailed explanation of how to use async functions in js. What are the precautions for using async functions in js. Here are practical cases, let’s take a look.
1. The ultimate solution
Asynchronous operation is a troublesome problem in JavaScript programming. It is so troublesome that some people have been proposing various solutions and trying to solve this problem.
From the earliest callback function, to the Promise object, and then to the Generator function, there has been improvement every time, but it feels incomplete. They all have additional complexities and require an understanding of the underlying underlying operating mechanisms of the abstraction.
Isn’t asynchronous I/O just reading a file? Why does it have to be so complicated? The highest state of asynchronous programming is that you don't have to worry about whether it is asynchronous at all.
async functions are the light at the end of the tunnel, considered by many to be the ultimate solution for asynchronous operations.
2. What is the async function?
In a word, async function is the syntactic sugar of Generator function.
There is a Generator function in the previous article, which reads two files in sequence.
var fs = require('fs'); var readFile = function (fileName){ return new Promise(function (resolve, reject){ fs.readFile(fileName, function(error, data){ if (error) reject(error); resolve(data); }); }); }; var gen = function* (){ var f1 = yield readFile('/etc/fstab'); var f2 = yield readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); };
Written as async function, as follows.
var asyncReadFile = async function (){ var f1 = await readFile('/etc/fstab'); var f2 = await readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); };
After comparison, you will find that the async function is to replace the asterisk (*) of the Generator function with async, and replace yield with await, and that’s it.
The improvements of async function to Generator function are reflected in the following three points.
(1) Built-in executor. The execution of the Generator function must rely on the executor, so there is the co function library, and the async function comes with its own executor. In other words, the execution of async functions is exactly the same as ordinary functions, with only one line.
var result = asyncReadFile();
(2) Better semantics. Async and await have clearer semantics than asterisk and yield. async means that there is an asynchronous operation in the function, and await means that the following expression needs to wait for the result.
(3) Wider applicability. According to the co function library convention, the yield command can only be followed by a Thunk function or a Promise object, while the await command of an async function can be followed by a Promise object and primitive type values (numeric values, stringsand Boolean values, but This is equivalent to a synchronous operation).
The implementation of async function is to wrap the Generator function and the automatic executor in a function.
async function fn(args){ // ... } // 等同于 function fn(args){ return spawn(function*() { // ... }); }
All async functions can be written in the second form above, where the spawn function is the automatic executor.
The implementation of the spawn function is given below, which is basically a replica of the previous automatic executor.
function spawn(genF) { return new Promise(function(resolve, reject) { var gen = genF(); function step(nextF) { try { var next = nextF(); } catch(e) { return reject(e); } if(next.done) { return resolve(next.value); } Promise.resolve(next.value).then(function(v) { step(function() { return gen.next(v); }); }, function(e) { step(function() { return gen.throw(e); }); }); } step(function() { return gen.next(undefined); }); }); }
The async function is a very new syntax feature that does not belong to ES6 but to ES7. Currently, it is still in the proposal stage, but the transcoders Babel and regenerator are already supported and can be used after transcoding.
Same as the Generator function, the async function returns a Promise object, and you can use the then method to add a callback function. When the function is executed, once it encounters await, it will return first, wait until the triggered asynchronous operation is completed, and then execute the subsequent statements in the function body.
Below is an example.
async function getStockPriceByName(name) { var symbol = await getStockSymbol(name); var stockPrice = await getStockPrice(symbol); return stockPrice; } getStockPriceByName('goog').then(function (result){ console.log(result); });
The above code is a function to obtain stock quotes. The async keyword in front of the function indicates that there are asynchronous operations inside the function. When this function is called, a Promise object is returned immediately.
The following example outputs a value after specifying the number of milliseconds.
function timeout(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function asyncPrint(value, ms) { await timeout(ms); console.log(value) } asyncPrint('hello world', 50);
The above code specifies that after 50 milliseconds, "hello world" will be output.
The Promise object behind the await command may result in rejected, so it is best to put the await command in try ...catch code block.
async function myFunction() { try { await somethingThatReturnsAPromise(); } catch (err) { console.log(err); } } // 另一种写法 async function myFunction() { await somethingThatReturnsAPromise().catch(function (err){ console.log(err); }); }
await command can only be used in async functions. If used in ordinary functions, an error will be reported.
async function dbFuc(db) { let docs = [{}, {}, {}]; // 报错 docs.forEach(function (doc) { await db.post(doc); }); }
上面代码会报错,因为 await 用在普通函数之中了。但是,如果将 forEach 方法的参数改成 async 函数,也有问题。
async function dbFuc(db) { let docs = [{}, {}, {}]; // 可能得到错误结果 docs.forEach(async function (doc) { await db.post(doc); }); }
上面代码可能不会正常工作,原因是这时三个 db.post 操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用 for 循环。
async function dbFuc(db) { let docs = [{}, {}, {}]; for (let doc of docs) { await db.post(doc); } }
如果确实希望多个请求并发执行,可以使用 Promise.all 方法。
async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = await Promise.all(promises); console.log(results); } // 或者使用下面的写法 async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = []; for (let promise of promises) { results.push(await promise); } console.log(results); }
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
The above is the detailed content of Detailed explanation of how to use async function in js. For more information, please follow other related articles on the PHP Chinese website!