手写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 - 成功态
rejected - 失败态

从上可知,状态只能由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个参数,成功的回调onFulfilledonRejected

    • 两个函数分别在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、快排、冒泡、单例模式+观察者模式相关推荐

  1. 【学习笔记】Part1·JavaScript·深度剖析-函数式编程与 JS 异步编程、手写 Promise(二、JavaScript 异步编程)

    [学习笔记]Part1·JavaScript·深度剖析-函数式编程与 JS 异步编程.手写 Promise(课前准备) [学习笔记]Part1·JavaScript·深度剖析-函数式编程与 JS 异步 ...

  2. python算法题排序_python-数据结构与算法- 面试常考排序算法题-快排-冒泡-堆排-二分-选择等...

    算法可视化网站推荐---->visualgo 0.面试题中的排序算法 一些排序算法可能在工作中用的会比较少,但是面试却是不得不面对的问题.算法有助于提高我们对数据结构的理解以及提高自己的逻辑能力 ...

  3. 手写Promise和all、race等方法,附上原理解析

    手写一个迷你版的Promise JavaScript 中的 Promise 诞生于 ES2015(ES6),是当下前端开发中特别流行的一种异步操作解决方案,简单实现一个迷你版本帮助深入理解 Promi ...

  4. 方法 手写promise_JS探索-手写Promise

    无意间在知乎上刷到Monad这个概念,去了解了一下,前端的Promise就是一种Monad模式,所以试着学习一下手写一个Promise. 本文内容主要参考于 只会用?一起来手写一个合乎规范的Promi ...

  5. 一个下课的时间带你手写promise!

    要手写前先看看用法,用法就是我们的需求 //直接调用 let promise=new Promise((resolve,reject)=>{resolve('123') }) promise.t ...

  6. 手写 Promise

    手写 Promise 实现一个简易版 Promise 在完成符合 Promise/A+ 规范的代码之前,我们可以先来实现一个简易版 Promise,因为在面试中,如果你能实现出一个简易版的 Promi ...

  7. 面试必备--手写Promise.all与.race

    最近面试被问到了手写Promise .all 与 Promise.race,奈何没有自己实现过,只能阿巴阿巴 面完之后,冷静下来思考了该如何实现,并把他写了下来(在实现过程中确实收获不少,让我对这两个 ...

  8. 【Promise】自定义 - 手写Promise - Promise.all - Promise(executor)

    手写Promise 1. 整体结构框架 2. Promise(executor) 3. Promise.prototype.then 4. Promise.prototype.catch 5. Pro ...

  9. c0语言 测试用例,按照 Promise/A+ 手写Promise,通过promises-aplus-tests的全部872个测试用例...

    本文主要讲述如何根据 Promises/A+ 规范,一步步手写一个 Promise 的 polyfill,代码中会配上对应的规范解释. 1. 定义需要的常量和工具方法// 1. 定义表示promsie ...

最新文章

  1. NVIDIA Jetson Xavier NX使用SD镜像刷机流程
  2. [认证授权] 5.OIDC(OpenId Connect)身份认证授权(扩展部分)
  3. 取得 Git 仓库 —— Git 学习笔记 04
  4. 研制一个生产计划编制的软件
  5. SDNU 1048.石子合并2(区间dp)
  6. MaskRCNN路标:TensorFlow版本用于抠图
  7. linux之自己总结学习linux的资源推荐
  8. YbtOJ#20060-[NOIP2020模拟赛B组Day3]字串修改【模拟】
  9. metinfo mysql_Metinfo 5.3.17 前台SQL注入漏洞
  10. 【转】switch中case与default的情况
  11. python怎么播放音乐_Python实现在线音乐播放器
  12. 系统集成项目管理工程师 笔记(第一章:信息化知识)
  13. 人人商城(分销版)1.11.7微擎原版,装修店铺后,网站链接失效,页面不显示数据
  14. 免费视频转文字-音频转文字软件:网易见外工作台, Speechnotes, autosub, Speech to Text, 百度语音识别
  15. 鸿蒙系统桌面加插件,华为鸿蒙OS 2系统最常用UI桌面模块化体验
  16. php mysql某小型汽车维修店信息管理系统zjyY3
  17. 不等式解集怎么取_(√)口诀巧取不等式组的解集
  18. 推送系统从0到1(八):个性化精准推送的实现
  19. 【Java】String字符串的最大长度是多少?
  20. Zotero(超好用的文献管理软件)安装+坚果云同步配置教程+常用插件介绍(全面)

热门文章

  1. java rc4_nodejs 和 java 进行 rc4 加密得到的结果不一样
  2. 如何安装ipython notebook_IPython notebook安装指导
  3. 服务器运维一般的故障率,服务器平均故障率
  4. java基础知识一_Java基础知识(一)
  5. java中组合_java中组合模式详解和使用方法
  6. 中专选计算机应用很难,对中专计算机应用基础改革的思考.pdf
  7. 【theano-windows】学习笔记二——theano中的函数和共享参数
  8. 移动端常见的一些兼容性问题
  9. ASP.NET Web API 中 特性路由(Attribute Routing) 的重名问题
  10. (周日赛)Sort the Array