手写promise
一种异步的解决方案, 参考
Promise代码基本结构
function Promise(executor){this.state = 'pending';this.value = undefined;this.reason = undefined;function resolve(){}function reject(){}
}
module.exports = Promise
state保存的是当前的状态,在Promise状态发展只有以下两种模式且不可逆:
从上可知,状态只能由pending变为resolved
(执行resolve)或pending变为rejected
(执行reject)
这就引出了resolve和reject的功能
function Promise(executor){this.state = 'pending'this.value = undefinedthis.reason = undefinedfunction resolve(value){this.state = 'resolved'this.value = value}function reject(reason){this.state = 'rejected'this.reason = reason}executor(resove, reject)
}
then方法的实现
当Promise的状态发生了改变,不论是成功或是失败都会调用then方法
let p = new Promise((resolve, reject)=>{setTimeout(()=>{resolve(1)},50)
})
p.then(data=>{console.log(data)})
可以得出then的方法,由于then方法是每个实例所以共有,因此可以将其写在原型链上:
- 接受2个参数,成功的回调
onFulfilled
和onRejected
- 两个函数分别在
resolved
状态下和rejected
状态下执行
- 两个函数分别在
Promise.prototype.then = function(onFulfilled, onRejected){if(this.state === 'resolved'){onFulfilled(this.value)}if(this.state === 'rejected'){onRejected(this.reason)}
}
当你写出了以上的代码,在同步的情况下执行完全没有问题. 但是在异步的情况下,流程如下:
- 函数执行
new Promise
,当遇到setTimeout
时,会将其推入一个异步队列中 - 然后执行p.then: 浏览器会顺着原型链找到
Promise.prototype.then
发现此时的状态是pending
,故不做任何处理,结束同步处理 - 开始执行异步队列里面的
setTimeout
,执行resovle(1)
.
异步方法的实现
处理异步方法的关键是,在Promise.prototype.then
方法中,当状态为pending
时,可以将处理函数作为变量存储起来,这样当异步过后,执行resolve
时,可以在内存中找到相应的处理函数并对其进行执行.
这就需要我们修改Promise构造函数
function Promise(exector){this.state = 'pending'this.value = undefinedthis.reason = undefinedthis.onResolvedCallbacks = [] // 用于存储成功的回调this.onRejectedCallbacks = [] // 用于存储失败的回调function resolve(value){if(this.state === 'pending'){this.state = 'resolved'this.value = valuethis.onResolvedCallbacks.forEach(resolved=> resolved(value))}}function reject(reason){if(this.state === 'pending'){this.state = 'rejected'this.reason = reasonthis.onRejectedCallbacks.forEach(rejected=> rejected(reason))}}
}// 修改 Promise.prototype.then
Promise.prototype.then = function (onFulfilled, onRejected){if(this.state === 'resolved'){onFulFilled(this.value)}if(this.state === 'rejected'){onRejected(this.reason)}// 异步: 将回调函数放入内存中.if(this.state === 'pending'){ if(typeof onFulfilled === 'function'){this.onResolvedCallbacks.push(onFulfilled)}if(typeof onRejected === 'function'){this.onRejectedCallbacks.push(onRejected)}}
}
当涉及到异步,使用this时要绝对小心
在使用setTimeout,里面回调使用的函数中的this是指向window的(通过debugger调试可以获得).这就需要在一开始时,将指向实例的this保存下来.
function Promise(exector){let _this = this_this.state = 'pending'_this.value = undefined_this.reason = undefined_this.onResovledCallbacks = []_this.onRejectedCallbacks = []function resolve(value){_this.state = 'resolved'_this.value = value_this.onResolvedCallbacks.forEach(resolved => resolved(value))}function reject(reason){_this.state = 'rejected'_this.reason = reason_this.onRejectedCallbacks.forEach(rejected=> rejected(reason))}exector(resolve, reject)
}
Promise.prototype.then = function(onFulfilled, onRejected){if(this.state === 'resolved'){onFulfilled(this.value)}if(this.state === 'rejected'){onRejected(this.reason)}if(this.state === 'pending'){if(typeof onFulfilled === 'function'){this.onResolvedCallbacks.push(onFulfilled)}if(typeof onRejected === 'function'){this.onRejectedCallbacks.push(onRejected)}}
}
快排
思路: 将每次的第一个元素作为基准,将比基准小的放在left数组中,比基准大的放在right数组中.然后返回[left, pivot,right]
function qSort(arr){let pivot,left = [],right = []function loop(arr){pivot = arr[0]left = []right = []for(let i=0, len = arr.length; i < len; i++){if(arr[i] > pivot){right.push(arr[i])} else{left.push(arr[i])}}return loop(left).concat(pivot, loop(right))}return loop(arr)
}
冒泡排序
思路:
- 记录待排序的数组长度 len
- 当len大于0时,会进入循环
- 会使用nextLen保存下次循环的长度.(为undefined会跳出循环)
- 每次循环都从第0号位开始,最后到len.
- 比较左右2边的元素
- 左 > 右: 则交换左右两边的位置,并将nextLen置为当前的下标
- 每次到循环结束,都会将len设为nextLen
function bubbleSort(arr){let len = arr.length;while(len > 0){let tmp,nextLenfor(let i =0 ; i< len; i++){if(arr[i]>arr[i+1]){tmp = arr[i]arr[i] = arr[i+1]arr[i+1] = tmpnextLen = i}len = nextLen}}return arr
}
单例模式实现 发布/订阅 模式
-
单例模式即只有一个实例
-
发布订阅模式,即使用
addDep
添加依赖.使用notify
class Observer{constructor(){this.events ={}}addDep(tag, handler){if(Array.isArray(this.events[tag])){// 是一个数组this.events[tag].push(handler)}else{this.events[tag] = [handler]}}notify(tag, params){this.events[tag].forEach(fn => fn(params))}
}
以上实现了一个简单的观察者模式,下面使用单例模式对其进行改造.
简单的说就是在使用new Observer
时,返回的是同一个实例.给构造函数添加一个获取单例的方法
class Observer{constructor(){this.events = {}this.instance = null}
}
Observetr.getInstance = function (){if(this.instance == null){this.instance = new Observer}return this.instance
}let o1 = Observetr.getInstance()
let o2 = Observetr.getInstance()
console.log(o1 === o2) // true