官术网_书友最值得收藏!

async/await

Rather than wrap fulfillment in a specialized data structure like a Promise with so many function blocks and parentheses and special contexts, why not simply make it so that asynchronous expressions can have their cake and eat it, too? These expressions do not block the process (asynchronous execution), but they nevertheless halt further execution of a program (synchronous) until resolved. 

The await operator is used to wait for a Promise. It only executes within an async function. The async/await concurrency modeling syntax has been available since Node 8.x. Here's a demonstration of async/await being used to replicate the preceding Promise.all example:

const db = {
getFullName: Promise.resolve('Jack Spratt'),
getAddress: Promise.resolve('10 Clean Street'),
getFavorites: Promise.resolve('Lean'),
}

async function profile() {
let fullName = await db.getFullName() // Jack Spratt
let address = await db.getAddress() // 10 Clean Street
let favorites = await db.getFavorites() // Lean

return {fullName, address, favorites};
}

profile().then(res => console.log(res) // results = ['Jack Spratt', '10 Clean Street', 'Lean'

Nice, right? You'll note that profile() returned a Promise. An async function always returns a Promise, though as we see here, the function itself can return anything it would like.

Promises and async/await work together like old pals. Here is a recursive directory walker that demonstrates this teamwork:

const {join} = require('path');
const {promisify} = require('util');
const fs = require('fs');
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);

async function $readDir (dir, acc = []) {
await Promise.all((await readdir(dir)).map(async file => {
file = join(dir, file);
return (await stat(file)).isDirectory() && acc.push(file) && $readDir(file, acc);
}));
return acc;
}

$readDir(`./dummy_filesystem`).then(dirInfo => console.log(dirInfo));

// [ 'dummy_filesystem/folderA',
// 'dummy_filesystem/folderB',
// 'dummy_filesystem/folderA/folderA-C' ]

It's a testament to how terse the code is for this recursive directory walker, that it is only slightly longer than the setup code above it. Since await expects a Promise, which Promise.all will return, run through every file that the readDir Promise returns, and map each file to another awaited Promise that will handle any recursive descent into subdirectories, updating the accumulator where appropriate. Read like this, the Promise.all((await readdir(dir)).map construct reads not unlike a basic looping construct, where deep asynchronous recursion  is being modelled in a simple and easy-to-follow procedural, synchronous way.

A pure Promise drop-in replacement version might look like this, assuming the same dependencies as the async/await version:

function $readDir(dir, acc=[]) {
return readdir(dir).then(files => Promise.all(files.map(file => {
file = join(dir, file);
return stat(file).then(fobj => {
if (fobj.isDirectory()) {
acc.push(file);
return $readDir(file, acc);
}
});
}))).then(() => acc);
};

Both versions are cleaner than what you would have with callbacks. The async/await version does take the best of both worlds, and creates a succinct representation resembling synchronous code, making it perhaps easier to follow and reason about.

Error handling with async/await is also quite easy, as it requires no special new syntax. With Promises and catch, there is a slight problem with synchronous code errors. Promises catch errors that occur in then blocks. If, for example, a third-party library your code is calling throws, that code is not wrapped by the Promise and that error will not be caught by catch.

With async/await, you can use the familiar try...catch statement:

async function makeError() {
try {
console.log(await thisDoesntExist());
} catch (error) {
console.error(error);
}
}

makeError();

This avoids all problems with special error-catching constructs. This native, rock-solid method will catch anything that throws anywhere in the try block, regardless of whether execution is synchronous or not. 

主站蜘蛛池模板: 桓仁| 吉首市| 兴国县| 句容市| 城市| 岳池县| 化德县| 东乡县| 北碚区| 洛浦县| 东兴市| 鹤壁市| 阿克苏市| 肃北| 临桂县| 大城县| 清镇市| 桑日县| 商城县| 云林县| 句容市| 乌鲁木齐县| 中西区| 宁陵县| 黄梅县| 高尔夫| 鄯善县| 永胜县| 河源市| 达尔| 青浦区| 玉树县| 临清市| 常熟市| 邹城市| 马公市| 旬阳县| 衡水市| 木兰县| 瑞丽市| 石楼县|