一是为了总结记录,二是为了以后面试能够逼逼,所以写下这文章。

一些操作

JavaScript异步编程所了解到的,有如下几种方式:回调函数事件发布订阅事件监听promisegeneratorasync, await

回调函数

定义:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。

咳咳…回调本质是种设计模式,回调函数可以用在同步场景下,也可以用在异步场景下。

同步阻塞场景

1
2
3
4
5
6
7
8
9
var func1 = function(callback){
(callback && typeof(callback) === 'function') && callback();
}

var func2 = function(){

}

func1(func2)

异步场景

1
2
3
4
5
6
7
8
9
10
11
12
function func1() {
console.log('func1');
}

function func2(callback) {
setTimeout(function(){
console.log('func2');
callback();
}, 500)
}

func2(func1);

事件发布订阅(观察者模式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 出版社
function Publisher() {
// 读者列表
this.subscribers = [];
}

Publisher.prototype.deliver = function(data) {
// 遍历当前出版社对象所有的订阅的方法
this.subscribers.forEach(function(fn) {
fn.fire(data);
})
return this;
}

// 观察者
function Observe(callback) {
this.fire = callback;
}

// 订阅者
Observe.prototype.subscribe = function(publisher) {
var that = this;
var alreadyExists = publisher.subscribers.some(function(el) {
return el.fire === that.fire;
});

if(!alreadyExists) {
publisher.subscribers.push(this);
}

console.log(publisher.subscribers)
return this;
}

// 订阅者退订
Observe.prototype.unsubscribe = function(publisher) {
var that = this;
publisher.subsribers = publisher.subscribers.filter(function(el) {
return !(el.fire === that.fire);
})
console.log(publisher.subcribers)
return this;
}

var publisher1 = new Publisher();

var Observer1 = new Observe(function(args) {
console.log(args);
})

observer1.subscribe(publisher1);

publisher1.deliver(123);

observer1.unsubsribe(publisher1)

一个读者对象都有一个通知方法,可以订阅多个出版社。出版社当然会有多个读者。

事件监听

DOM事件也是一类重要的异步过程,采用事件驱动模式。

1
2
3
4
var button = document.getElementById('btn');
button.addEventListener('click', function() {
conosole.log('click')
})

从异步角度,addEventListener函数就是异步过程的发起函数,事件监听器函数就是异步过程的回调函数。事件触发时,表示异步任务完成,监听器函数将等待主线程执行。

promise

使用promise,只需要异步任务返回一个promise对象即可。该对象有一个then方法,允许指方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 创建promise对象,接受两个回调函数
var promise = new Promise(function(resolve, reject){
if(xxx) {
resolve(value);
} else {
reject(error);
}
});

promise.then(function(value) {
// success
} , function(value) {
// error
})

// 同时执行两个`promise`任务,在它们完成后执行`then`
Promise.all([p1, p2]).then(function(result){
console.log(result) // 获得一个Array [p1, p2]
})

// 同时执行两个`promise`任务,选择最先返回的结果
Promise.all([p1, p2]).then(function(result){
console.log(result) // p1
})

generator

generator函数最大的特点是可以交出函数的执行权(暂停执行)。

1
2
3
4
5
6
7
8
9
10
11
12
let tell = function* (){
yield 'a';
yield 'b';
return 'c';
}

let k = tell()

console.log(k.next()) // {done: false, value: "a"}
console.log(k.next()) // {done: false, value: "b"}
console.log(k.next()) // {done: false, value: "c"}
console.log(k.next()) // {done: true, value: undefined}

整个generator函数就是一个封装的异步任务,或者说是异步任务的容器。

next方法的作用是分阶段执行generator函数。每次调用next方法,会返回一个对象,表示当前阶段的信息(value 属性和 done 属性)。
value属性是yield语句后面表达式的值,表示当前阶段的值;done属性是一个布尔值,表示 generator函数是否执行完毕,即是否还有下一个阶段。

async await

1
2
3
4
5
6
7
8
9
10
11
12
13
let state = async function (){
while(1){
await 'a';
await 'b';
await 'c';
}
}
let status=state();
console.log(status.next()); // {done: false, value: "a"}
console.log(status.next()); // {done: false, value: "b"}
console.log(status.next()); // {done: false, value: "c"}
console.log(status.next()); // {done: false, value: "a"}
console.log(status.next()); // {done: false, value: "b"}

async await 更多的是generator函数的特性,自己体会下