一是为了总结记录,二是为了以后面试能够逼逼,所以写下这文章。
一些操作
JavaScript异步编程所了解到的,有如下几种方式:回调函数
、事件发布订阅
、事件监听
、promise
、generator
、async, 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
| var promise = new Promise(function(resolve, reject){ if(xxx) { resolve(value); } else { reject(error); } });
promise.then(function(value) { } , function(value) { })
Promise.all([p1, p2]).then(function(result){ console.log(result) })
Promise.all([p1, p2]).then(function(result){ console.log(result) })
|
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()) console.log(k.next()) console.log(k.next()) console.log(k.next())
|
整个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()); console.log(status.next()); console.log(status.next()); console.log(status.next()); console.log(status.next());
|
async await 更多的是generator函数的特性,自己体会下
node的stream
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
| const Readable = require('stream').Readable const rs = new Readable
function wait(time) { return new Promise((resolve) => { setTimeout(() => { resolve() }, time) }) }
const source = 'aiopshdviaowefipoajsdpoghapeisfhlasdfasdf'.split('')
rs._read = function () { !!source.length && wait(100) .then(() => { if (source.length > 1) { rs.push(source.shift()) } else { rs.push(source.shift()) rs.push('\n') rs.push(null) } }) }
rs.pipe(process.stdout)
|