史上最完整的promise源码实现,哈哈,之所以用这个标题,是因为开始用的标题《手写promise源码》不被收录

promise自我介绍

promise : "君子一诺千金,承诺的事情一定会去执行"

promise的使用场景

  • 使用promise能够有效的解决js异步回调地狱问题
  • 能够将业务逻辑与数据处理分隔开使代码更优雅,方便阅读,更有利于代码维护

promise的基本用法

  1. function promiseTest() {
  2. let promise = new Promise((resolve, reject) => {
  3. let r = parseInt(Math.random() * 10)
  4. if (r % 2 == 0) {
  5. resolve('成功')
  6. } else {
  7. reject('失败')
  8. }
  9. })
  10. return promise
  11. }
  12. const promise = promiseTest()
  13. promise.then((data) => {
  14. console.log(data)
  15. }).catch((err) => {
  16. console.log(err)
  17. })

先来分析一下promise的规范

  • promise有三种状态:pending,fulfilled,rejected。pending代表等待的状态,在此状态下,可能执行resolve()的方法,也可能执行reject()方法,fulfilld代表成功态,此状态下执行resolve()方法,rejected代表失败态,此状态下执行reject()方法,一旦成功了就不能失败,反过来也是一样
  • 每个promsie都有一个then方法
  • 如果new promise 报错了会走失败态(throw new Error('报错')也会走失败态)
  1. // 手写promise源码
  2. // 第一步:基础代码
  3. class Mypromise {
  4. constructor(executor) {
  5. this.state = 'pending' //状态值
  6. this.value = undefined //成功的返回值
  7. this.reason = undefined //失败的返回值
  8. // 成功
  9. let resolve = (value) => {
  10. if (this.state == 'pending') {
  11. this.state = 'fullFilled'
  12. this.value = value
  13. }
  14. }
  15. // 失败
  16. let reject = (reason) => {
  17. if (this.state == 'pending') {
  18. this.state = 'rejected'
  19. this.reason = reason
  20. }
  21. }
  22. try {
  23. // 执行函数
  24. executor(resolve, reject)
  25. } catch (err) {
  26. // 失败则直接执行reject函数
  27. reject(err)
  28. }
  29. }
  30. then(onFullFilled, onRejected) {
  31. // 状态为fulfuilled,执行onFullFilled,传入成功的值
  32. if (this.state == 'fullFilled') {
  33. onFullFilled(this.value)
  34. }
  35. // 状态为rejected,执行onRejected,传入失败的值
  36. if (this.state == 'rejected') {
  37. onRejected(this.reason)
  38. }
  39. }
  40. }
  41. const p = new Mypromise((resolve, reject) => {
  42. // resolve('success') // 走了成功就不会走失败了
  43. throw new Error('失败') // 失败了就走resolve
  44. reject('failed') // 走了失败就不会走成功
  45. })
  46. p.then((res) => {
  47. console.log(res)
  48. }, (err) => {
  49. console.log(err)
  50. })

此时九阳神功的第一层就算完成了

但是当碰到异步调用的时候,上面的代码就会卡在pending态,神功初成,还要继续往下修炼,若不能继续突破,则无法上升到第二层境界

如下调用的时候会卡住,无法执行

  1. const p = new Mypromise((resolve, reject) => {
  2. setTimeout(function() {
  3. resolve('success')
  4. }, 1000)
  5. })
  6. p.then((res) => {
  7. console.log(res)
  8. }, (err) => {
  9. console.log(err)
  10. })

此时我们使用一个发布订阅者模式,在pending状态的时候将成功的函数和失败的函数存到各自的回调队列数组中,等一旦reject或者resolve,就调用它们:

在pending态的时候将所有的要在成功态执行的方法都存到onResolveCallbacks数组中

当状态变化的时候,就执行发布他们

下面是完整的代码

  1. class Mypromise {
  2. constructor(executor) {
  3. this.status = 'pending' //状态值
  4. this.value = undefined //成功的返回值
  5. this.reason = undefined //失败的返回值
  6. this.onResolvedCallbacks = [] //成功的回调函数
  7. this.onRejectedCallbacks = [] //失败的回调函数
  8. // 成功
  9. let resolve = (value) => {
  10. // pending用来屏蔽的,resolve和reject只能调用一个,不能同时调用,这就是pending的作用
  11. if (this.status == 'pending') {
  12. this.status = 'fullFilled'
  13. this.value = value
  14. // 发布执行函数
  15. this.onResolvedCallbacks.forEach(fn => fn())
  16. }
  17. }
  18. // 失败
  19. let reject = (reason) => {
  20. if (this.status == 'pending') {
  21. this.status = 'rejected'
  22. this.reason = reason
  23. //失败执行函数
  24. this.onRejectedCallbacks.forEach(fn => fn())
  25. }
  26. }
  27. try {
  28. // 执行函数
  29. executor(resolve, reject)
  30. } catch (err) {
  31. // 失败则直接执行reject函数
  32. reject(err)
  33. }
  34. }
  35. then(onFullFilled, onRejected) {
  36. // 同步
  37. if (this.status == 'fullFilled') {
  38. onFullFilled(this.value)
  39. }
  40. if (this.status == 'rejected') {
  41. onRejected(this.reason)
  42. }
  43. // 异步
  44. if (this.status == 'pending') {
  45. // 在pending状态的时候先订阅
  46. this.onResolvedCallbacks.push(() => {
  47. // todo
  48. onFullFilled(this.value)
  49. })
  50. this.onRejectedCallbacks.push(() => {
  51. // todo
  52. onRejected(this.reason)
  53. })
  54. }
  55. }
  56. }
  57. const p = new Mypromise((resolve, reject) => {
  58. setTimeout(function() {
  59. // resolve('success') // 异步调用的时候,this.status一直是pending状态,不会执行代码了,因此要改装成发布订阅者模式
  60. reject('failed')
  61. }, 1000)
  62. // resolve('success') // 走了成功就不会走失败了
  63. // throw new Error('失败') // 失败了也会走resolve
  64. // reject('failed')
  65. })
  66. p.then((res) => {
  67. console.log(res)
  68. }, (err) => {
  69. console.log(err)
  70. })
  71. p.then((res) => {
  72. console.log(res)
  73. }, (err) => {
  74. console.log(err)
  75. })
  76. p.then((res) => {
  77. console.log(res)
  78. }, (err) => {
  79. console.log(err)
  80. })

恭喜你少年,九阳神功第二层你已经学会了

接下来接续学习神功第三层promise的链式调用

要达到链式调用我们就要采用“老和尚给小和尚讲故事”的递归大法了,也可以说是愚公移山大法,很多同学可能一直对递归函数有点惧怕,其实很简单,想一下小时候听过的老和尚讲故事,以及愚公移山的故事就清楚什么是递归算法了。

我们先来回味一下这两个经典的故事:

“老和尚给小和尚讲故事:从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,从前有座山,山里有座庙......”

愚公说:“虽我之死,有子存焉;子又生孙,孙又生子;子又有子,子又有孙;子子孙孙无穷匮也,而山不加增,何苦而不平”

递归是不是很简单呢?

不了解规范的同学先去看一下Promises/A+规范文档:

英文规范文档:https://promisesaplus.com/

下面先来分析一下链式调用的用法,以及then里面可能出现的情况

  1. const p = new Promise((resolve, reject) => {
  2. resolve(100)
  3. })
  4. p.then((data) => {
  5. return 100 * data
  6. }, (err) => {
  7. console.log(err)
  8. }).then((data) => {
  9. return new Promise((resolve, reject) => {
  10. console.log(data)
  11. resolve(data)
  12. })
  13. }).then((data) => {
  14. console.log('result', data) // 10000
  15. })

根据原生promise的then的用法,我们总结一下:

1.then方法如果返回一个普通的值,我们就将这个普通值传递给下一个then

2.then方法如果返回一个promise对象,我们就将这个promise对象执行结果返回到下一个then

普通的值传递很好办,我们将第一次then的onFulfilled函数返回的值存到x变量里面,在然后resolve出去就可以了

  1. then(onFullFilled, onRejected) {
  2. // 这样就是一个递归
  3. let promise2 = new Mypromise((resolve, reject) => {
  4. // 函数里面调函数就跟第一次使用一样,主要的是这里面的this指向怎么变化的
  5. // 同步
  6. let x
  7. console.log('this', this)
  8. if (this.status == 'fullFilled') {
  9. // 箭头函数,无论this一直是指向最外层的对象
  10. x = onFullFilled(this.value)
  11. resolve(x) // resolve(x) // 这一步x只能处理普通值,但是x可能是一个函数对象,或者promise,所以要对x进行判断
  12. // 添加一个resolvePromise()的方法来判断x跟promise2的状态,决定promise2是走成功还是失败
  13. }
  14. if (this.status == 'rejected') {
  15. x = onRejected(this.reason)
  16. reject(x)
  17. }
  18. // 异步
  19. if (this.status == 'pending') {
  20. // 在pending状态的时候先订阅
  21. this.onResolvedCallbacks.push(() => {
  22. // todo
  23. x = onFullFilled(this.value)
  24. resolve(x)
  25. })
  26. this.onRejectedCallbacks.push(() => {
  27. // todo
  28. x = onRejected(this.reason)
  29. resolve(x)
  30. })
  31. }
  32. })
  33. return promise2 //then方法返回一个promise对象
  34. }

复杂的是then里面返回的是一个promise的时候怎么办,因为返回的promise的我们要判断他执行的状态,来决定是走成功态,还是失败态,这时候我们就要写一个判断的函数resolvePromise(promise2, x, resolve, reject)来完成这个判断

  1. then(onFullFilled, onRejected) {
  2. // 这样就是一个递归
  3. let promise2 = new Mypromise((resolve, reject) => {
  4. // 箭头函数,无论this一直是指向最外层的对象
  5. // 同步
  6. let x
  7. if (this.status == 'fullFilled') {
  8. setTimeout(() => {
  9. try {
  10. x = onFullFilled(this.value)
  11. // 添加一个resolvePromise()的方法来判断x跟promise2的状态,决定promise2是走成功还是失败
  12. resolvePromise(promise2, x, resolve, reject)
  13. } catch (err) { // 中间任何一个环节报错都要走reject()
  14. reject(err)
  15. }
  16. }, 0) // 同步无法使用promise2,所以借用setiTimeout异步的方式
  17. // MDN 0>=4ms
  18. }
  19. if (this.status == 'rejected') {
  20. setTimeout(() => {
  21. try {
  22. x = onRejected(this.value)
  23. resolvePromise(promise2, x, resolve, reject)
  24. } catch (err) { // 中间任何一个环节报错都要走reject()
  25. reject(err)
  26. }
  27. }, 0) // 同步无法使用promise2,所以借用setiTimeout异步的方式
  28. }
  29. // 异步
  30. if (this.status == 'pending') {
  31. // 在pending状态的时候先订阅
  32. this.onResolvedCallbacks.push(() => {
  33. // todo
  34. setTimeout(() => {
  35. try {
  36. x = onFullFilled(this.value)
  37. resolvePromise(promise2, x, resolve, reject)
  38. } catch (err) { // 中间任何一个环节报错都要走reject()
  39. reject(err)
  40. }
  41. }, 0) // 同步无法使用promise2,所以借用setiTimeout异步的方式
  42. })
  43. this.onRejectedCallbacks.push(() => {
  44. // todo
  45. setTimeout(() => {
  46. try {
  47. x = onRejected(this.value)
  48. resolvePromise(promise2, x, resolve, reject)
  49. } catch (err) { // 中间任何一个环节报错都要走reject()
  50. reject(err)
  51. }
  52. }, 0) // 同步无法使用promise2,所以借用setiTimeout异步的方式
  53. })
  54. }
  55. })
  56. return promise2
  57. }

下面再来实现核心的resolvePromise方法

这个方法的主要作用是用来判断x的值,如果x的值是一个普通的值,就直接返回x的值,如果x的值是一个promise,就要返回x.then() 执行的结果,核心代码如下

  1. const resolvePromise = (promise2, x, resolve, reject) => {
  2. // x和promise2不能是同一个人,如果是同一个人就报错
  3. if (promise2 === x) {
  4. return reject(
  5. new TypeError('Chaining cycle detected for promise #<promise>')
  6. )
  7. }
  8. // 判断如果x是否是一个对象,判断函数是否是对象的方法有:typeof instanceof constructor toString
  9. if (typeof x === 'object' && x != null || typeof x === 'function') {
  10. try {
  11. let then = x.then // 取then可以报错,报错就走reject()
  12. if (typeof then === 'function') {
  13. // 用then.call()为了避免在使用一次x.then报错
  14. then.call(x, y => {
  15. console.log('y', y)
  16. resolve(y)// 采用promise的成功结果,并且向下传递
  17. }, r => {
  18. reject(r)// 采用promise的失败结果,并且向下传递
  19. })
  20. } else {
  21. resolve(x)// x不是一个函数,是一个对象
  22. }
  23. } catch (err) {
  24. reject(err)
  25. }
  26. } else {
  27. // x是一个普通值
  28. resolve(x)
  29. }
  30. }

细节的地方看注释

此时基本的情况都已经实现的差不多了,下面还一种如下的情况,x的值里面包含有promise

  1. const p2 = p.then((data) => {
  2. return new Mypromise((resolve, reject) => {
  3. resolve(new Mypromise((resolve, reject) => {
  4. setTimeout(() => {
  5. resolve(data * 1000)
  6. }, 1000)
  7. }))// 这里很可能又是一个promise函数
  8. })
  9. })

我们只需要在判断x的值的时候多调用一个回调,就可以解决以上的问题

下面是完整的源码:

  1. const isFunction = (value) => typeof value === 'function'
  2. const PENDING = 'pending'
  3. const RESOLVED = 'fulFilled'
  4. const REJECTED = 'rejected'
  5. const resolvePromise = (promise2, x, resolve, reject) => {
  6. // x和promise2不能是同一个人,如果是同一个人就报错
  7. // 加一个开关,防止多次调用失败和成功,跟pending状态值一样的逻辑一样,走了失败就不能走成功了,走了成功一定不能在走失败
  8. if (promise2 === x) {
  9. return reject(
  10. new TypeError('Chaining cycle detected for promise #<promise>')
  11. )
  12. }
  13. // 判断如果x是否是一个对象,判断函数是否是对象的方法有:typeof instanceof constructor toString
  14. if ((typeof x === 'object' && x != null) || typeof x === 'function') {
  15. let called
  16. try { // 预防取.then的时候错误
  17. let then = x.then // Object.definePropertype
  18. if (typeof then === 'function') {
  19. // 用then.call()为了避免在使用一次x.then报错
  20. then.call(x, y => {
  21. // resolve(y)// 采用promise的成功结果,并且向下传递
  22. if (called) {
  23. return
  24. }
  25. called = true
  26. // y有可能是一个promise,那么我们就要继续使用回调函数,直到解析出来的值是一个普通值
  27. resolvePromise(promise2, y, resolve, reject)
  28. }, r => {
  29. if (called) {
  30. return
  31. }
  32. called = true
  33. reject(r)// 采用promise的失败结果,并且向下传递
  34. })
  35. } else {
  36. if (called) {
  37. return
  38. }
  39. called = true
  40. resolve(x)// x不是一个函数,是一个对象
  41. }
  42. } catch (err) {
  43. if (called) {
  44. return
  45. }
  46. called = true
  47. reject(err)
  48. }
  49. } else {
  50. // x是一个普通值
  51. resolve(x)
  52. }
  53. }
  54. class MyPromise {
  55. constructor(executor) {
  56. this.status = PENDING
  57. this.value = undefined
  58. this.reason = undefined
  59. this.onResolvedCallbacks = []
  60. this.onRejectedCallbacks = []
  61. // 成功
  62. let resolve = (value) => {
  63. // pending最屏蔽的,resolve和reject只能调用一个,不能同时调用,这就是pending的作用
  64. if (this.status == PENDING) {
  65. this.status = RESOLVED
  66. this.value = value
  67. // 发布执行函数
  68. this.onResolvedCallbacks.forEach(fn => fn())
  69. }
  70. }
  71. // 失败
  72. let reject = (reason) => {
  73. if (this.status == PENDING) {
  74. this.status = REJECTED
  75. this.reason = reason
  76. this.onRejectedCallbacks.forEach(fn => fn())
  77. }
  78. }
  79. try {
  80. // 执行函数
  81. executor(resolve, reject)
  82. } catch (err) {
  83. // 失败则直接执行reject函数
  84. reject(err)
  85. }
  86. }
  87. then(onFulFilled, onRejected) {
  88. // onfulfilled, onrejected 都是可选参数
  89. onFulFilled = isFunction(onFulFilled) ? onFulFilled : data => data
  90. onRejected = isFunction(onRejected) ? onRejected : err => {
  91. throw err
  92. }
  93. let promise2 = new MyPromise((resolve, reject) => {
  94. // 箭头函数,无论this一直是指向最外层的对象
  95. // 同步
  96. if (this.status == RESOLVED) {
  97. setTimeout(() => {
  98. try {
  99. let x = onFulFilled(this.value)
  100. // 添加一个resolvePromise()的方法来判断x跟promise2的状态,决定promise2是走成功还是失败
  101. resolvePromise(promise2, x, resolve, reject)
  102. } catch (err) { // 中间任何一个环节报错都要走reject()
  103. reject(err)
  104. }
  105. }, 0) // 同步无法使用promise2,所以借用setiTimeout异步的方式
  106. // MDN 0>=4ms
  107. }
  108. if (this.status == REJECTED) {
  109. setTimeout(() => {
  110. try {
  111. let x = onRejected(this.reason)
  112. resolvePromise(promise2, x, resolve, reject)
  113. } catch (err) { // 中间任何一个环节报错都要走reject()
  114. reject(err)
  115. }
  116. }, 0) // 同步无法使用promise2,所以借用setiTimeout异步的方式
  117. }
  118. // 异步
  119. if (this.status == PENDING) {
  120. // 在pending状态的时候先订阅
  121. this.onResolvedCallbacks.push(() => {
  122. // todo
  123. setTimeout(() => {
  124. try {
  125. let x = onFulFilled(this.value)
  126. resolvePromise(promise2, x, resolve, reject)
  127. } catch (err) { // 中间任何一个环节报错都要走reject()
  128. reject(err)
  129. }
  130. }, 0) // 同步无法使用promise2,所以借用setiTimeout异步的方式
  131. })
  132. this.onRejectedCallbacks.push(() => {
  133. // todo
  134. setTimeout(() => {
  135. try {
  136. let x = onRejected(this.reason)
  137. resolvePromise(promise2, x, resolve, reject)
  138. } catch (err) { // 中间任何一个环节报错都要走reject()
  139. reject(err)
  140. }
  141. }, 0) // 同步无法使用promise2,所以借用setiTimeout异步的方式
  142. })
  143. }
  144. })
  145. return promise2
  146. }
  147. }

到此核心的代码就写完了,我们用promises-aplus-tests插件来检测一下

安装:npm install promises-aplua-tests -g插件

加上如下代码:

  1. MyPromise.defer = MyPromise.deferred = function() {
  2. let dfd = {}
  3. dfd.promise = new MyPromise((resolve, reject) => {
  4. dfd.resolve = resolve
  5. dfd.reject = reject
  6. })
  7. return dfd
  8. }
  9. module.exports = MyPromise

执行命令:promises-aplus-tests promise.js

ok,非常完美

到此核心的代码都已经实现了,后面的静态方法,catch,all,race,resolve,reject,finally方法就是小试牛刀了,就不在赘述,只贴上代码

catch方法:

  1. // catch方法
  2. MyPromise.prototype.catch = function(onReJected) {
  3. // 返回一个没有第一个参数的then方法
  4. return this.then(undefined, onReJected)
  5. }

promise的all方法

  1. // 写一个判断函数是否是一个promise的方法
  2. const isPromise = (value) => {
  3. if ((value != null && typeof value === 'object') || typeof value === 'function') {
  4. if (typeof value.then == 'function') {
  5. return true
  6. }
  7. } else {
  8. return false
  9. }
  10. }
  11. // static all方法
  12. MyPromise.all = (lists) => {
  13. // 返回一个promise
  14. return new MyPromise((resolve, reject) => {
  15. let resArr = [] // 存储处理的结果的数组
  16. // 判断每一项是否处理完了
  17. let index = 0
  18. function processData(i, data) {
  19. resArr[i] = data
  20. index += 1
  21. if (index == lists.length) {
  22. // 处理异步,要使用计数器,不能使用resArr==lists.length
  23. resolve(resArr)
  24. }
  25. }
  26. for (let i = 0; i < lists.length; i++) {
  27. if (isPromise(lists[i])) {
  28. lists[i].then((data) => {
  29. processData(i, data)
  30. }, (err) => {
  31. reject(err) // 只要有一个传入的promise没执行成功就走reject
  32. return
  33. })
  34. } else {
  35. processData(i, lists[i])
  36. }
  37. }
  38. })
  39. }

promise的race方法

  1. // promise的race方法
  2. // 两个方法赛跑,哪个赢了就先返回哪个的状态
  3. MyPromise.race = (lists) => {
  4. return new MyPromise((resolve, reject) => {
  5. for (let i = 0; i < lists.length; i++) {
  6. if (isPromise(lists[i])) {
  7. lists[i].then((data) => {
  8. resolve(data)// 哪个先完成就返回哪一个的结果
  9. return
  10. }, (err) => {
  11. reject(err)
  12. return
  13. })
  14. } else {
  15. resolve(lists[i])
  16. }
  17. }
  18. })
  19. }

promise的静态方法resolve()

  1. // 静态resolve方法
  2. MyPromise.resolve = (value) => {
  3. // 如果是一个promise对象就直接将这个对象返回
  4. if (isPromise(value)) {
  5. return value
  6. } else {
  7. // 如果是一个普通值就将这个值包装成一个promise对象之后返回
  8. return new MyPromise((resolve, reject) => {
  9. resolve(value)
  10. })
  11. }
  12. }

promise的reject()方法

  1. // 静态reject方法
  2. MyPromise.reject = (value) => {
  3. return new MyPromise((resolve, reject) => {
  4. reject(value)
  5. })
  6. }

promise的finally方法

  1. // 终极方法finally finally其实就是一个promise的then方法的别名,在执行then方法之前,先处理callback函数
  2. MyPromise.prototype.finally = function(cb) {
  3. return this.then(
  4. value => MyPromise.resolve(cb()).then(() => value)
  5. ,
  6. reason => MyPromise.reject(cb()).then(() => { throw reason })
  7. )
  8. }

少年,恭喜你promise神功已经修炼大成,是不是以为自己很牛逼,可以下山去行走江湖,劫富济贫,铲奸除恶了,莫急,修炼成promise大法,还只是刚刚开始,前面还有很多大法等着你呢,还有很多怪等你去打完,升级,学不会,就别先想着下山去吧,无论什么时候都要记住,山外有山,天外有天,技术精进一刻也不能怠慢。

史上最完整promise源码手写实现的更多相关文章

  1. HashMap源码分析(史上最详细的源码分析)

    HashMap简介 HashMap是开发中使用频率最高的用于映射(键值对 key value)处理的数据结构,我们经常把hashMap数据结构叫做散列链表: ObjectI entry<Key, ...

  2. 这一次,彻底理解Promise源码思想

    关于Promise的源码实现,网上有太多答案,我也看过很多资料,但都不是很明白.直到有一天我学完函数式编程之函子的概念,才对Promise源码有了更深刻的认识.今天,就让我们来重新认识一下Promis ...

  3. JAVAWEB贵美网上商城完整项目源码(SSH2)

    JAVAWEB贵美网上商城完整项目源码(SSH2) 贵美网上商城原是北大青鸟的一个内部项目,项目采用 struts2+spring4+hibernate4+MySQL等技术实现,数据库连接池采用c3p ...

  4. 在Ubuntu Server14.04上编译Android6.0源码

    此前编译过Android4.4的源码,但是现在Android都到了7.0的版本,不禁让我感叹Google的步伐真心难跟上,趁这周周末时间比较充裕,于是在过去的24小时里,毅然花了9个小时编译了一把An ...

  5. 从.src.rpm包中提取出完整的源码的方法

    1 什么是完整的源码 就是说,最初始的源码加上打了所有的patch后的源码,即最新的源码. 2 过程 2.1 从.src.rpm中提取完整的rpm工程文件 2.1.1 rpm to cpio rpm2 ...

  6. Git 把码云上被fork项目源码merge到fork出来的分支项目

    Git 把码云上被fork项目源码merge到fork出来的分支项目 By:授客 QQ:1033553122 需求描述 被fork的项目有更新代码,希望把更新的代码merge到fork分支项目 解决方 ...

  7. Promise源码实现与测试

    const PENDING = 'pending', FULFILLED = 'fulfilled', REJECTED = 'rejected' class MyPromise { construc ...

  8. 【commons-pool2源码】写前思考

    写作的初衷 工作4年多, 一直没有系统的阅读过优秀的开源代码, 所以从今年开始做一些尝试, 阅读源码并且试着将自己的理解以文章的形式输出, 从而达到以下目的: 通过阅读源码提升自身的技术水准, 通过写 ...

  9. 设计比较好,有助于学习的Github上的iOS App源码 (中文)

    Github版 中文 : TeamTalk 蘑菇街. 开源IM. 电商强烈推荐. MyOne-iOS 用OC写的<一个> iOS 客户端 zhihuDaily 高仿知乎日报 Coding ...

随机推荐

  1. Win10最详细的优化设置 完美解决磁盘100%占用

    1.用360优化win10后开不了机的问题原因是禁用了三个服务:在360应用软件服务里dmwappushsvc.diagnsticsTrackingservice.coreMessaging这三个要开 ...

  2. .NET Core sdk和runtime区别

    SDK和runtime区别 .net core Runtime[跑netcore 程序的] (CoreCLR) .net core SDK (开发工具包 [runtime(jre) + Rolysn( ...

  3. Java进阶——Java中的字符串常量池

    转载. https://blog.csdn.net/qq_30379689/article/details/80518283 字符串常量池 JVM为了减少字符串对象的重复创建,其内部维护了一个特殊的内 ...

  4. C++ 二叉搜索树原理及其实现

    首先是概念:二叉搜索树又称二叉排序树,它具有以下的性质: 若是左子树不为空,则左子树上所有节点的值小于根节点的值 若是右子树不为空,则右子树上所有结点的值大于根节点的值 二叉搜索树的左右子树也是二叉搜 ...

  5. DS 红黑树详解

    通过上篇博客知道,二叉搜索树的局限在于不能完成自平衡,从而导致不能一直保持高性能. AVL树则定义了平衡因子绝对值不能大于1,使二叉搜索树达到了严格的高度平衡. 还有一种能自我调整的二叉搜索树, 红黑 ...

  6. Windows 上的应用程序在运行期间可以给自己改名(可以做 OTA 自我更新)

    原文:Windows 上的应用程序在运行期间可以给自己改名(可以做 OTA 自我更新) 程序如何自己更新自己呢?你可能会想到启动一个新的程序或者脚本来更新自己.然而 Windows 操作系统允许一个应 ...

  7. java之 代理设计模式

    1. 设计一个案例来实现租房功能.分析:在租房的过程中涉及到了3个对象,房东,中介,房客. 中介和房客具有相同的功能--租房. 可以设计如下: 2.上图的设计实际上就是一个代理设计模式---静态代理设 ...

  8. Java中Date、String、Calendar类型之间的转化

    1.Calendar 转化 String   //获取当前时间的具体情况,如年,月,日,week,date,分,秒等   Calendar calendat = Calendar.getInstanc ...

  9. mysql 5.7 非正常安装,无法启动 服务没有报告任何错误

    以前,完整安装mysql5.7程序时,由于程序太大,可以将安装缓存目录中的安装文件(较小)复制出来后,留以后使用. mysql--win32.msi 2 mysql-5.7.17-winx64.msi ...

  10. 利用nfs-client-provisioner动态提供Kubernetes后端存储卷

    原文:https://www.kubernetes.org.cn/3894.html 利用NFS client provisioner动态提供Kubernetes后端存储卷 本文翻译自nfs-clie ...