你与弄懂promise之间可能只差这篇文章(一)
promise诞生之前:
因为JS引擎在执行js代码时只分配了一个线程去执行,所以Javascript是单线程的。由于有这个前置设定,前端er在书写代码时绕不开的一件事是就是----如何处理异步,即处理“现在和稍后”关系的问题,事实上我们每一天都在与异步逻辑打交道。
在promise出现之前,前端er基本上都是通过callback的方式来解决“稍后”的问题,例如有经典的“发布-订阅”模式,观察者模式,他们都运用了传入回调函数的高阶函数。vue2.x源码在实现数据双向绑定时就是运用的发布-订阅模式。
我们先来看看三个例子。(例子均在node环境中运行, 其中name.txt中的内容是"kk", age.txt中的内容是10。)
1 . 回调函数(callback)。fs读取文件的先后顺序是不固定的,我们无法判断哪个文件先读取完成。此例实现的是,在完全读取两个文件的内容之后进行某个操作(例如console个啥的)。
let fs = require('fs'); let arr = []; let after = (times, cb) => { return (data) => { arr.push(data); if (--times === 0) { cb(arr) } } } let on = after(2, (arr) => { console.log('我是在全部读取了2个文件内容之后打印出来的, ', arr) }) fs.readFile('name.txt', 'utf8', (err, data) => { on(data) }) fs.readFile('age.txt', 'utf8', (err, data) => { on(data) }) 结果: 我是在全部读取了2个文件内容之后打印出来的, [ 'kk', '10' ]。 说明: 这种写法的问题在于,需要依靠计数来执行回调函数里面的内容。我们先得这计算出有几个异步操作,然后统计出来在全部的异步操作完成后再执行回调。
2 .发布-订阅模式。订阅的时候添加订阅者,发布的时候执行相应的订阅函数。此例实现的是,在特定的时候emit了某事件,订阅了该事件的回调函数继而执行。
class EventEmitter { constructor () { this.subs = {} } on (eventName, cb) { if (!this.subs[eventName]) { this.subs[eventName] = [] } this.subs[eventName].push((...args) => cb(...args)) } emit (eventName, ...args) { if (this.subs[eventName]) { this.subs[eventName].forEach(cb => cb(...args)) } else { throw Error(`没有订阅${eventName}这个事件`) } } } const event = new EventEmitter(); let fs = require('fs'); event.on('kk-event', (...args) => { fs.readFile('name.txt', 'utf8', (err, data) => { console.log('data1', data, ...args) }) }) event.on('kk-event', (...args) => { fs.readFile('age.txt', 'utf8', (err, data) => { console.log('data2', data, ...args) }) }) event.emit('kk-event', 123, 456) 结果: data1 kk 123 456 data2 10 123 456
3 . 观察者模式。它与发布-订阅两者本质是一样的,只不过观察者模式在写法上强调观察者和被观察者之间的关系,而发布-订阅模式则没有这样的关系。此例实现的是,在被观察者的状态发生变化后,观察者执行自己的update方法进行更新。
class Subject { constructor() { this.observers = []; this.state = ''; // 假设观察者观察的是被观察者的state } setState (status) { // 当state变化时出发观察者的update方法 this.state = status; this.notify(); } attach (observer) { this.observers.push(observer) // 与发布-订阅不同的是,这里添加的是一个个观察者实例,这就将被观察者和观察者之间关联了起来 } notify () { this.observers.forEach(observe => observe.update()) // 在被观察者状态变化时,调用更新的是观察者的update方法 } } class Observer { constructor (name, target) { this.name = name; this.target = target; } update () { console.log(`通知${this.name},被观察者状态变化,所以观察者${this.name}跟着变化`) } } let fs = require('fs'); let subject = new Subject(); let observer1 = new Observer('kk1', subject); let observer2 = new Observer('kk2', subject); subject.attach(observer1); subject.attach(observer2); subject.setState('B'); 结果: 通知kk1,被观察者状态变化,所以观察者kk1跟着变化 通知kk2,被观察者状态变化,所以观察者kk2跟着变化
相关推荐
前端开发Kingcean 2020-07-30
zhjn0 2020-11-24
夜斗不是神 2020-11-17
学习web前端 2020-11-09
waiwaiLILI 2020-11-03
raidtest 2020-10-09
myccc 2020-09-24
jzlixiao 2020-09-15
guicaizhou 2020-09-15
digwtx 2020-09-14
大秦铁骑 2020-08-19
thatway 2020-08-19
lovecodeblog 2020-08-19
codetyper 2020-08-16
comwayLi 2020-08-16
MongoDB数据库 2020-08-16
cjsyrwt 2020-08-14
Tristahong 2020-08-05