简要介绍:异步贯穿了整个js,从ES5到ES6,ES7,也有很多为了解决异步的尝试。
1、异步的几种实现方法
(1)回调函数
var fs=require('fs');
fs.read('url',function(err,data){
fs.read('url',function(err,data){
})
})
这是一个简单的基于回调实现异步的过程,我们发现一旦异步嵌套过深,会导致“回调地狱”。
(2)事件监听
(3)发布订阅(类似于emit,on观察者模式)
(4)ES6的promise
var readFile = require('fs-readfile-promise');
readFile(fileA)
.then(function (data) {
console.log(data.toString());
})
.then(function () {
return readFile(fileB);
})
.then(function (data) {
console.log(data.toString());
})
.catch(function (err) {
console.log(err);
});
2、ES6中通过Generator实现异步
缺点:
(1)需要Thrunk转换器,将函数转换成Thunk
(2)需要引入CO模块才能自动执行Generator函数
总之,通过定义Generator并且使之能够自动执行,Genetator实现异步还是比较麻烦的。
3、ES7中的提案,通过async实现异步操作
(1)async异步的基本用法:
async function Person(name){
await getTimeDelay();
console.log(name)
}
async function getTimeDelay(){
return new Promise(function(resolve,reject){
setTimeout(resolve(),500);
})
}
上面是一个简单的通过async实现异步的简单例子,我们将console.log延迟了500ms之后进行。
async函数的声明方式有很多种:
/ 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)
// Class 的方法
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}
(2)async的函数返回的是promise对象
async function sayHello(){
return 'hello yuxl'
}
sayHello().then(data){
console.log(data)//输出的结果为hello yuxl
}
规定async函数执行后返回的是一个promise,如果是字符串等非primise类型,则会尝试转化为promise。
(3)async函数的错误处理
如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject。
async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了
如果想防止出错,则可以将await模块放在try,catch中:
async function f() {
try {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
} catch(e) {
}
return await('hello world');
}