ES8系列目录
- 1 async函数
- 2 Promise.prototype.finally()
- 3 Object.values(),Object.entries()
- 4 Object.getOwnPropertyDescriptors()
- 5 字符串填充 padStart和padEnd
- 6 函数参数列表与调用中的尾部逗号
- 7 共享内存与原子操作
所有整理的文章都收录到我《Cute-JavaScript》系列文章中,访问地址:http://js.pingan8787.com
1 async函数
1.1 介绍
ES8引入 async
函数,是为了使异步操作更加方便,其实它就是Generator函数的语法糖。
async
函数使用起来,只要把Generator函数的(*)号换成 async
, yield
换成 await
即可。对比如下:
-
// Generator写法
-
const fs = require('fs');
-
const readFile = function (fileName) {
-
return new Promise(function (resolve, reject) {
-
fs.readFile(fileName, function(error, data) {
-
if (error) return reject(error);
-
resolve(data);
-
});
-
});
-
};
-
const gen = function* () {
-
const f1 = yield readFile('/etc/fstab');
-
const f2 = yield readFile('/etc/shells');
-
console.log(f1.toString());
-
console.log(f2.toString());
-
};
-
// async await写法
-
const asyncReadFile = async function () {
-
const f1 = await readFile('/etc/fstab');
-
const f2 = await readFile('/etc/shells');
-
console.log(f1.toString());
-
console.log(f2.toString());
-
};
对比Genenrator有四个优点:
- (1)内置执行器 Generator函数执行需要有执行器,而
async
函数自带执行器,即 async
函数与普通函数一模一样:
-
async f();
- (2)更好的语义
async
和 await
,比起 星号
和 yield
,语义更清楚了。 async
表示函数里有异步操作, await
表示紧跟在后面的表达式需要等待结果。 - (3)更广的适用性
yield
命令后面只能是 Thunk 函数或 Promise 对象,而 async
函数的 await
命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。 - (4)返回值是Promise
async
函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用 then
方法指定下一步的操作。
进一步说, async
函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而 await
命令就是内部 then
命令的语法糖。
1.2 基本用法
async
函数返回一个Promise对象,可以使用 then
方法添加回调函数,函数执行时,遇到 await
就会先返回,等到异步操作完成,在继续执行。
-
async function f(item){
-
let a = await g(item);
-
let b = await h(item);
-
return b;
-
}
-
f('hello').then(res => {
-
console.log(res);
-
})
async
表明该函数内部有异步操作,调用该函数时,会立即返回一个Promise对象。
另外还有个定时的案例,指定时间后执行:
-
function f (ms){
-
return new Promise(res => {
-
setTimeout(res, ms);
-
});
-
}
-
async function g(val, ms){
-
await f(ms);
-
console.log(val);
-
}
-
g('leo', 50);
async
函数还有很多使用形式:
-
// 函数声明
-
async function f (){...}
-
// 函数表达式
-
let f = async function (){...}
-
// 对象的方法
-
let a = {
-
async f(){...}
-
}
-
a.f().then(...)
-
// Class的方法
-
class c {
-
constructor(){...}
-
async f(){...}
-
}
-
// 箭头函数
-
let f = async () => {...}
1.3 返回Promise对象
async
内部 return
返回的值会作为 then
方法的参数,另外只有 async
函数内部的异步操作执行完,才会执行 then
方法指定的回调函数。
-
async function f(){
-
return 'leo';
-
}
-
f().then(res => { console.log (res) }); // 'leo'
async
内部抛出的错误,会被 catch
接收。
-
async function f(){
-
throw new Error('err');
-
}
-
f().then (
-
v => console.log(v),
-
e => console.log(e)
-
)
-
// Error: err
1.4 await命令
通常 await
后面是一个Promise对象,如果不是就返回对应的值。
-
async function f(){
-
return await 10;
-
}
-
f().then(v => console.log(v)); // 10
我们常常将 asyncawait
和 try..catch
一起使用,并且可以放多个 await
命令,也是防止异步操作失败因为中断后续异步操作的情况。
-
async function f(){
-
try{
-
await Promise.reject('err');
-
}catch(err){ ... }
-
return await Promise.resolve('leo');
-
}
-
f().then(v => console.log(v)); // 'leo'
1.5 使用注意
- (1)
await
命令放在 try...catch
代码块中,防止Promise返回 rejected
。 - (2)若多个
await
后面的异步操作不存在继发关系,最好让他们同时执行。
-
// 效率低
-
let a = await f();
-
let b = await g();
-
// 效率高
-
let [a, b] = await Promise.all([f(), g()]);
-
// 或者
-
let a = f();
-
let b = g();
-
let a1 = await a();
-
let b1 = await b();
- (3)
await
命令只能用在 async
函数之中,如果用在普通函数,就会报错。
-
// 错误
-
async function f(){
-
let a = [{}, {}, {}];
-
a.forEach(v =>{ // 报错,forEach是普通函数
-
await post(v);
-
});
-
}
-
// 正确
-
async function f(){
-
let a = [{}, {}, {}];
-
for(let k of a){
-
await post(k);
-
}
-
}
2 Promise.prototype.finally()
finally()
是ES8中Promise添加的一个新标准,用于指定不管Promise对象最后状态(是 fulfilled
还是 rejected
)如何,都会执行此操作,并且 finally
方法必须写在最后面,即在 then
和 catch
方法后面。
-
// 写法如下:
-
promise
-
.then(res => {...})
-
.catch(err => {...})
-
.finally(() => {...})
finally
方法常用在处理Promise请求后关闭服务器连接:
-
server.listen(port)
-
.then(() => {..})
-
.finally(server.stop);
本质上,finally方法是then方法的特例:
-
promise.finally(() => {...});
-
// 等同于
-
promise.then(
-
result => {
-
// ...
-
return result
-
},
-
error => {
-
// ...
-
throw error
-
}
-
)