javascript --- 手写Promise、快排、冒泡、单例模式+观察者模式
手写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
javascript --- 手写Promise、快排、冒泡、单例模式+观察者模式相关推荐
- 【学习笔记】Part1·JavaScript·深度剖析-函数式编程与 JS 异步编程、手写 Promise(二、JavaScript 异步编程)
[学习笔记]Part1·JavaScript·深度剖析-函数式编程与 JS 异步编程.手写 Promise(课前准备) [学习笔记]Part1·JavaScript·深度剖析-函数式编程与 JS 异步 ...
- python算法题排序_python-数据结构与算法- 面试常考排序算法题-快排-冒泡-堆排-二分-选择等...
算法可视化网站推荐---->visualgo 0.面试题中的排序算法 一些排序算法可能在工作中用的会比较少,但是面试却是不得不面对的问题.算法有助于提高我们对数据结构的理解以及提高自己的逻辑能力 ...
- 手写Promise和all、race等方法,附上原理解析
手写一个迷你版的Promise JavaScript 中的 Promise 诞生于 ES2015(ES6),是当下前端开发中特别流行的一种异步操作解决方案,简单实现一个迷你版本帮助深入理解 Promi ...
- 方法 手写promise_JS探索-手写Promise
无意间在知乎上刷到Monad这个概念,去了解了一下,前端的Promise就是一种Monad模式,所以试着学习一下手写一个Promise. 本文内容主要参考于 只会用?一起来手写一个合乎规范的Promi ...
- 一个下课的时间带你手写promise!
要手写前先看看用法,用法就是我们的需求 //直接调用 let promise=new Promise((resolve,reject)=>{resolve('123') }) promise.t ...
- 手写 Promise
手写 Promise 实现一个简易版 Promise 在完成符合 Promise/A+ 规范的代码之前,我们可以先来实现一个简易版 Promise,因为在面试中,如果你能实现出一个简易版的 Promi ...
- 面试必备--手写Promise.all与.race
最近面试被问到了手写Promise .all 与 Promise.race,奈何没有自己实现过,只能阿巴阿巴 面完之后,冷静下来思考了该如何实现,并把他写了下来(在实现过程中确实收获不少,让我对这两个 ...
- 【Promise】自定义 - 手写Promise - Promise.all - Promise(executor)
手写Promise 1. 整体结构框架 2. Promise(executor) 3. Promise.prototype.then 4. Promise.prototype.catch 5. Pro ...
- c0语言 测试用例,按照 Promise/A+ 手写Promise,通过promises-aplus-tests的全部872个测试用例...
本文主要讲述如何根据 Promises/A+ 规范,一步步手写一个 Promise 的 polyfill,代码中会配上对应的规范解释. 1. 定义需要的常量和工具方法// 1. 定义表示promsie ...
最新文章
- NVIDIA Jetson Xavier NX使用SD镜像刷机流程
- [认证授权] 5.OIDC(OpenId Connect)身份认证授权(扩展部分)
- 取得 Git 仓库 —— Git 学习笔记 04
- 研制一个生产计划编制的软件
- SDNU 1048.石子合并2(区间dp)
- MaskRCNN路标:TensorFlow版本用于抠图
- linux之自己总结学习linux的资源推荐
- YbtOJ#20060-[NOIP2020模拟赛B组Day3]字串修改【模拟】
- metinfo mysql_Metinfo 5.3.17 前台SQL注入漏洞
- 【转】switch中case与default的情况
- python怎么播放音乐_Python实现在线音乐播放器
- 系统集成项目管理工程师 笔记(第一章:信息化知识)
- 人人商城(分销版)1.11.7微擎原版,装修店铺后,网站链接失效,页面不显示数据
- 免费视频转文字-音频转文字软件:网易见外工作台, Speechnotes, autosub, Speech to Text, 百度语音识别
- 鸿蒙系统桌面加插件,华为鸿蒙OS 2系统最常用UI桌面模块化体验
- php mysql某小型汽车维修店信息管理系统zjyY3
- 不等式解集怎么取_(√)口诀巧取不等式组的解集
- 推送系统从0到1(八):个性化精准推送的实现
- 【Java】String字符串的最大长度是多少?
- Zotero(超好用的文献管理软件)安装+坚果云同步配置教程+常用插件介绍(全面)
热门文章
- java rc4_nodejs 和 java 进行 rc4 加密得到的结果不一样
- 如何安装ipython notebook_IPython notebook安装指导
- 服务器运维一般的故障率,服务器平均故障率
- java基础知识一_Java基础知识(一)
- java中组合_java中组合模式详解和使用方法
- 中专选计算机应用很难,对中专计算机应用基础改革的思考.pdf
- 【theano-windows】学习笔记二——theano中的函数和共享参数
- 移动端常见的一些兼容性问题
- ASP.NET Web API 中 特性路由(Attribute Routing) 的重名问题
- (周日赛)Sort the Array