es6异步函数

异步与同步

异步: 所谓异步,简单来说就是 不能连续执行,上一个任务没运行完,下一个任务照样运行,任务之间不能连续,不能首尾相连。
同步: 同步则与异步相反,是 连续执行 的,下一个任务紧接着上一个任务之后运行,如果上一个任务没有运行完,下一个任务没法运行。

异步的解决方案

1、回调函数

当我们需要在执行的函数中进行其他的操作,就需要用到回调函数了。如:

function fn(args, callback){
	//TODO...
	callback();
}

fn(args, ()=> {
	//TODO...
})

2、事件监听

如DOM事件的监听、鼠标键盘的事件监听等,都是异步执行的。

document.addEventListener("click", (e)=>{
	//TODO...
}, false)

3、发布/订阅

比如我要开一家新公司,供用户加入,当我在新公司发布消息时,只有注册用户才能收到消息。
我们架构程序时,我们可以从使用出发,比如先写我们要怎么用,如:

// 首先要开新公司
const company = new Company();

// 然后需要有些用户吧,比如用户A、B等等
// 用户A
const userA = function(msg){
	console.log(`用户A接收到的消息为:${msg}`)
}

// 用户B
const userB = function(msg){
	console.log(`用户B接收到的消息为:${msg}`)
}

// 再接着把这些用户注册到新公司里(他们就是这公司的注册用户了)
company.addSubscribe(userA, userB);

// 这样我就可以以公司的名义向用户发送消息了吧
company.release('今天公司成立,注册用户每人奖励一万元整。');

然后接下来我们是不是要考虑怎么实现这个Company啦(就是注册这公司有些什么样的手续及后续的功能)。如:

// 首先我们是不是要定义一个这样的类啊
class Company {
	constructor(){
		// 在类里面我们要定义一个存储用户数据的变量
		this.users = [];
	}
	// 前面我们用到的添加用户的功能
	addSubscribe(...args){
		args.forEach((val) => {
            if(!this.users.includes(val)){
                this.users.push(val);
            }
        })

        return this;
	}
	// 还需要发布消息的功能吧
	release(msg){
		this.users.forEach((fn) => {
            fn(msg);
        })

        return this;
	}	
}

4、Promise(es6新增)

es6新增的异步处理,如果按第1项里的回调函数,如果多层调用会很麻烦,如ajax:

// 比如我们要先获取token,再根据token去获取用户信息,然后根据用户信息获取其他的内容等等
// 就得这样(这样一直嵌套感觉很不爽)
ajax(option, (res) => {
	// 拿到token
	ajax(option, (res) => {
		// 拿到用户信息
		ajax(option, (res) => {
			// 拿到其他等等数据
		})
	})
})

那么在es6里面我们可以怎么做呢,Promise的语法什么的我就不说了,我只讲思路。
如:

// 封装一个ajax方法
function myAjax(option){
	return new Promise((resolve, reject) => {
		ajax(option, (res) => {
			resolve(res);
		}, (err) => {
			reject(err);
		})
	});
}

// 此时我用这个方法去完成上面的需求
myAjax(option).then(res => {
	// 拿到token
	return myAjax(res.token);
}).then(res => {
	// 拿到用户信息
	return myAjax(res.info);
}).then(res => {
	// 拿到其他等等数据
	console.log(res);
})

generator函数(es6新增)

简单来说,她是个可控制运行的函数,函数体内的内容是可控的。你叫她往下运行她就往下运行。来看一个简单的例子:

function* idMaker(){
    let index = 0;
    while(true)
        yield index++;
}

let gen = idMaker(); // 返回 generator 对象
// gen.next()方法,返回 yield 表达式产生的值
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// ...

有人就会问了,平时咋用啊,貌似也用不到吧。那我们就结合上面Ajax,来实现一个类似需求,我们经常会遇到在一个内容很多的页面上,我们是不是需要先加载什么后加载什么呢,比如我们得先把菜单列表的数据请求过来,再去请求新闻啊、活动啊之类的,对吧。那么我们来看看怎么玩。

// 这里我们直接用上面封装的myAjax方法
// 首先我们要定义一个generator函数
function* gen(){
	yield myAjax(option); // 请求菜单
	yield myAjax(option); // 请求新闻
	yield myAjax(option); // 请求活动
}

let g = gen();
g.next().value.then(res => {
	console.log('菜单请求成功');
	return g.next().value; // 菜单请求成功之后,接着往下请求
}).then(res => {
	console.log('新闻请求成功');
	return g.next().value; // 新闻请求成功之后,接着往下请求
}).then(res => {
	console.log('活动请求成功');
})
// 看完是不是感觉跟前面的Promise一样啊,对,没错,就是一样的。唯一不同的是什么呢,我们把请求的参数放上一块了(option放到了gen函数里面了),这样就方便代码管理啦。

但是呢,每次都要手机调用,也很麻烦,再说了,generator语言化也不怎么友好,比如“*”号啥意思?“yield”关键字又是啥意思?感觉不符合场景。有更好的东东吗?当然有,请接着往下看!

async、await(es6新增)

没错,就是她了,字面意思已经告诉你了 “async”异步的意思,“await”等待。那她怎么用呢,看例子:

// 这里我们还是直接用上面封装的myAjax方法
// 定义一个异步函数
async function fn(){
	let token = await myAjax(option); // 拿到token
	let info = await myAjax(token); // 根据token去拿用户信息.
	let other = await myAjax(info); // 根据info去拿其他信息
}
// 最后我们再调用这个函数
fn() // async函数,返回的是一个Promise对象,你看哪儿哪儿都有Promise,是不是很重要
// 那么既然是一个Promise对象,可不可以.then 或 .catch啊,当然可以
async function fn2(){
	return 'allen'
}
fn2().then(res => {
	console.log(res); // allen
})
// 这样是不是方便很多,语义化也很好啊。

这里有几个点需要注意:
1、await只能放在async函数中。
2、await后面可以是任何对象
3、async函数返回的是一个Promise对象
4、如果await后面的Promise状态变为reject,那么会停止整个async函数

总结

总的来说,以后常用的估计就是Promise与async函数、await的配合使用了,当然我们首先得了解Promise,了解异步。谢谢大家。

注:爱护原创,转载请说明出处

你可能感兴趣的:(javascript,es6)