区块链技术博客
www.b2bchain.cn

六、6. Promise 的封装求职学习资料

D0b2wT.gif

本文介绍了六、6. Promise 的封装求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

我们自己封装一个 Promise 对象有一定的难度。

但是只要我们抓住封装的核心思想:如何封装与如何使用息息相关,事情就会变得简单。

来分析一下:

以图片加载为例,Promise 的使用如下

function imageLoad = function(url) {   const img = new Image()   img.src = url   return new Promise((resolve, reject) => {     img.onload = function() {       resolve('图片加载成功')     }     img.onerror = function() {       resolve('图片加载失败')     }   }) }

封装好之后,我们就可以利用 imageLoad 来执行图片加载完成之后的逻辑

imageLoad('xxx.png').then(res => {   console.log(res) // 此时的 res 为字符串:图片加载成功 }) .catch(err => {   console.log(err) // 此时的 err 为字符串:图片加载失败 })

我们要抓住的核心关键是: Promise 最终的目的是,是为了执行 then 中的回调函数,我们给它取个名字为 then_cb

因此,我们就应该思考,如何在 Promise 对象内部,让 then_cb 执行。

显而易见,Promise 对象中,包含有原型方法 then,构造函数需要传入回调函数 executor:该回调函数包含两个参数,resolve 与 reject。

因此我们可以依据这些已知点,得到如下结果:

class MyPromise {   constroctor(executor) {     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {}    _reject(value) {}    then(then_cb) {} }

我们目的是为了让 then_cb 执行。因此我们要回到 imageLoad 里, 去思考它的执行时机在哪里?

此时我们在 imageLoad 中发现,执行时机,只有 resolve

我们添加了一个 onload 事件的监听,当图片加载成功时,执行 resolve。

很显然,我们可以得出结论,then_cb 的执行需要被 resolve 触发。

但是目前来看,如果没有额外的手段,resolve 是无法执行 then_cb 的。要怎么办?

最简单的解决方案就是在 then 中抛出引用,在 resolve 中执行该引用。于是代码演变如下:

class MyPromise {   constructor(executor) {     this.thencallback = null     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     this.thencallback(value)   }    _reject(value) { }    then(then_cb) {     this.thencallback = then_cb   } }

同理,继续演变,解决 catch 的执行问题。

class MyPromise {   constructor(executor) {     this.thencallback = null     this.rejectcallback = null     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     this.thencallback(value)   }    _reject(value) {     this.rejectcallback(value)   }    then(then_cb, onRejected) {     this.thencallback = then_cb     this.rejectcallback = onRejected   }    catch(onRejected) {     this.then(null, onRejected)   } }

如果不追求别的特性的话,我们的 Promise 对象就已经封装好,并且可以使用了。

写个例子简单验证一下

const p = new MyPromise((resolve, reject) => {   setTimeout(() => {     reject('异常信息')   }, 1000) })  p.then(res => {   console.log(res) })

完全符合预期。

然后简单调整,模拟将 then_cb 放入队列中执行,简单调整如下:

class MyPromise {   constructor(executor) {     this.thencallback = null     this.rejectcallback = null     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     setTimeout(() => {       this.thencallback(value)     }, 0)   }    _reject(value) {     setTimeout(() => {       this.rejectcallback(value)     }, 0)   }    then(then_cb, onRejected) {     this.thencallback = then_cb     this.rejectcallback = onRejected   }    catch(onRejected) {     this.then(null, onRejected)   } }

如果在面试中,被问到如何手写 Promise,实在想不起来,就把这段最简单的代码丢出去,基本上也能拿不错的高分啦。按照我的思路来想,十分简单。

将 Promise 的三种状态以及传递的值加入,让代码更规范一点

pending -> resolved

pending -> rejected

const pending = 'PENDING' const resolved = 'RESOLVED' const rejected = 'REJECTED'  class MyPromise2 {   constructor(executor) {     this.thencallback = undefined     this.rejectcallback = undefined     this._value = undefined     this._status = pending     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     if (!pending) return     this._status = resolved     this._value = value     setTimeout(() => {       this.thencallback(value)     }, 0)   }    _reject(value) {     if (!pending) return     this._status = rejected     this._value = rejected     setTimeout(() => {       this.rejectcallback(value)     }, 0)   }    then(then_cb, onRejected) {     this.thencallback = then_cb     console.log(then_cb)     this.rejectcallback = onRejected   }    catch(onRejected) {     this.then(null, onRejected)   } }  window.MyPromise2 = MyPromise2

then 可以多次调用,因此,缓存 then 的回调的引用,对应的应该是一个队列/数组。这样才能保证多次调用的 then_cb 都能执行。

因此,收集回调的 then 方法 与执行回调的 _resolve/_reject 都需要进行简单的调整

基于这个思路继续优化。

const pending = 'PENDING' const resolved = 'RESOLVED' const rejected = 'REJECTED'  const isFunction = (fn) => typeof fn === 'function'  class MyPromise2 {   constructor(executor) {     this.onResolvedQueue = []     this.onRejectedQueue = []     this._value = undefined     this._status = pending     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     if (!pending) return     const run = () => {       this._status = resolved       let cb;       // 执行队列中收集的回调,执行一个,删除一个,       // 队列思路:先进先出       while (cb = this.onResolvedQueue.shift()) {         this._value = value         cb(value)       }     }      setTimeout(run, 0)   }    _reject(value) {     if (!pending) return     const run = () => {       this._status = rejected       this._value = value       if (this.onRejectedQueue.length == 0) {         throw new Error(value)       }       let cb       while(cb = this.onRejectedQueue.shift()) {         cb(value)       }     }      setTimeout(run, 0)   }    then(onResolved, onRejected) {     // 根据不同的状态执行不同的逻辑     if (this._status === pending) {       if (isFunction(onResolved)) {         this.onResolvedQueue.push(onResolved)       }        if (isFunction(onRejected)) {         this.onRejectedQueue.push(onRejected)       }     }   }    catch(onRejected) {     this.then(null, onRejected)   } }  window.MyPromise2 = MyPromise2

验证一下,完美通过。
“`js
const p = new MyPromise2((resolve, reject) => {
setTimeout(() => {
resolve(‘xxx’)
}, 1000)
})

p.then(res => {
console.log(res)
})

p.then(res => {
console.log(‘2 then’, res)

我们自己封装一个 Promise 对象有一定的难度。

但是只要我们抓住封装的核心思想:如何封装与如何使用息息相关,事情就会变得简单。

来分析一下:

以图片加载为例,Promise 的使用如下

function imageLoad = function(url) {   const img = new Image()   img.src = url   return new Promise((resolve, reject) => {     img.onload = function() {       resolve('图片加载成功')     }     img.onerror = function() {       resolve('图片加载失败')     }   }) }

封装好之后,我们就可以利用 imageLoad 来执行图片加载完成之后的逻辑

imageLoad('xxx.png').then(res => {   console.log(res) // 此时的 res 为字符串:图片加载成功 }) .catch(err => {   console.log(err) // 此时的 err 为字符串:图片加载失败 })

我们要抓住的核心关键是: Promise 最终的目的是,是为了执行 then 中的回调函数,我们给它取个名字为 then_cb

因此,我们就应该思考,如何在 Promise 对象内部,让 then_cb 执行。

显而易见,Promise 对象中,包含有原型方法 then,构造函数需要传入回调函数 executor:该回调函数包含两个参数,resolve 与 reject。

因此我们可以依据这些已知点,得到如下结果:

class MyPromise {   constroctor(executor) {     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {}    _reject(value) {}    then(then_cb) {} }

我们目的是为了让 then_cb 执行。因此我们要回到 imageLoad 里, 去思考它的执行时机在哪里?

此时我们在 imageLoad 中发现,执行时机,只有 resolve

我们添加了一个 onload 事件的监听,当图片加载成功时,执行 resolve。

很显然,我们可以得出结论,then_cb 的执行需要被 resolve 触发。

但是目前来看,如果没有额外的手段,resolve 是无法执行 then_cb 的。要怎么办?

最简单的解决方案就是在 then 中抛出引用,在 resolve 中执行该引用。于是代码演变如下:

class MyPromise {   constructor(executor) {     this.thencallback = null     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     this.thencallback(value)   }    _reject(value) { }    then(then_cb) {     this.thencallback = then_cb   } }

同理,继续演变,解决 catch 的执行问题。

class MyPromise {   constructor(executor) {     this.thencallback = null     this.rejectcallback = null     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     this.thencallback(value)   }    _reject(value) {     this.rejectcallback(value)   }    then(then_cb, onRejected) {     this.thencallback = then_cb     this.rejectcallback = onRejected   }    catch(onRejected) {     this.then(null, onRejected)   } }

如果不追求别的特性的话,我们的 Promise 对象就已经封装好,并且可以使用了。

写个例子简单验证一下

const p = new MyPromise((resolve, reject) => {   setTimeout(() => {     reject('异常信息')   }, 1000) })  p.then(res => {   console.log(res) })

完全符合预期。

然后简单调整,模拟将 then_cb 放入队列中执行,简单调整如下:

class MyPromise {   constructor(executor) {     this.thencallback = null     this.rejectcallback = null     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     setTimeout(() => {       this.thencallback(value)     }, 0)   }    _reject(value) {     setTimeout(() => {       this.rejectcallback(value)     }, 0)   }    then(then_cb, onRejected) {     this.thencallback = then_cb     this.rejectcallback = onRejected   }    catch(onRejected) {     this.then(null, onRejected)   } }

如果在面试中,被问到如何手写 Promise,实在想不起来,就把这段最简单的代码丢出去,基本上也能拿不错的高分啦。按照我的思路来想,十分简单。

将 Promise 的三种状态以及传递的值加入,让代码更规范一点

pending -> resolved

pending -> rejected

const pending = 'PENDING' const resolved = 'RESOLVED' const rejected = 'REJECTED'  class MyPromise2 {   constructor(executor) {     this.thencallback = undefined     this.rejectcallback = undefined     this._value = undefined     this._status = pending     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     if (!pending) return     this._status = resolved     this._value = value     setTimeout(() => {       this.thencallback(value)     }, 0)   }    _reject(value) {     if (!pending) return     this._status = rejected     this._value = rejected     setTimeout(() => {       this.rejectcallback(value)     }, 0)   }    then(then_cb, onRejected) {     this.thencallback = then_cb     console.log(then_cb)     this.rejectcallback = onRejected   }    catch(onRejected) {     this.then(null, onRejected)   } }  window.MyPromise2 = MyPromise2

then 可以多次调用,因此,缓存 then 的回调的引用,对应的应该是一个队列/数组。这样才能保证多次调用的 then_cb 都能执行。

因此,收集回调的 then 方法 与执行回调的 _resolve/_reject 都需要进行简单的调整

基于这个思路继续优化。

const pending = 'PENDING' const resolved = 'RESOLVED' const rejected = 'REJECTED'  const isFunction = (fn) => typeof fn === 'function'  class MyPromise2 {   constructor(executor) {     this.onResolvedQueue = []     this.onRejectedQueue = []     this._value = undefined     this._status = pending     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     if (!pending) return     const run = () => {       this._status = resolved       let cb;       // 执行队列中收集的回调,执行一个,删除一个,       // 队列思路:先进先出       while (cb = this.onResolvedQueue.shift()) {         this._value = value         cb(value)       }     }      setTimeout(run, 0)   }    _reject(value) {     if (!pending) return     const run = () => {       this._status = rejected       this._value = value       if (this.onRejectedQueue.length == 0) {         throw new Error(value)       }       let cb       while(cb = this.onRejectedQueue.shift()) {         cb(value)       }     }      setTimeout(run, 0)   }    then(onResolved, onRejected) {     // 根据不同的状态执行不同的逻辑     if (this._status === pending) {       if (isFunction(onResolved)) {         this.onResolvedQueue.push(onResolved)       }        if (isFunction(onRejected)) {         this.onRejectedQueue.push(onRejected)       }     }   }    catch(onRejected) {     this.then(null, onRejected)   } }  window.MyPromise2 = MyPromise2

验证一下,完美通过。
“`js
const p = new MyPromise2((resolve, reject) => {
setTimeout(() => {
resolve(‘xxx’)
}, 1000)
})

p.then(res => {
console.log(res)
})

p.then(res => {
console.log(‘2 then’, res)

我们自己封装一个 Promise 对象有一定的难度。

但是只要我们抓住封装的核心思想:如何封装与如何使用息息相关,事情就会变得简单。

来分析一下:

以图片加载为例,Promise 的使用如下

function imageLoad = function(url) {   const img = new Image()   img.src = url   return new Promise((resolve, reject) => {     img.onload = function() {       resolve('图片加载成功')     }     img.onerror = function() {       resolve('图片加载失败')     }   }) }

封装好之后,我们就可以利用 imageLoad 来执行图片加载完成之后的逻辑

imageLoad('xxx.png').then(res => {   console.log(res) // 此时的 res 为字符串:图片加载成功 }) .catch(err => {   console.log(err) // 此时的 err 为字符串:图片加载失败 })

我们要抓住的核心关键是: Promise 最终的目的是,是为了执行 then 中的回调函数,我们给它取个名字为 then_cb

因此,我们就应该思考,如何在 Promise 对象内部,让 then_cb 执行。

显而易见,Promise 对象中,包含有原型方法 then,构造函数需要传入回调函数 executor:该回调函数包含两个参数,resolve 与 reject。

因此我们可以依据这些已知点,得到如下结果:

class MyPromise {   constroctor(executor) {     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {}    _reject(value) {}    then(then_cb) {} }

我们目的是为了让 then_cb 执行。因此我们要回到 imageLoad 里, 去思考它的执行时机在哪里?

此时我们在 imageLoad 中发现,执行时机,只有 resolve

我们添加了一个 onload 事件的监听,当图片加载成功时,执行 resolve。

很显然,我们可以得出结论,then_cb 的执行需要被 resolve 触发。

但是目前来看,如果没有额外的手段,resolve 是无法执行 then_cb 的。要怎么办?

最简单的解决方案就是在 then 中抛出引用,在 resolve 中执行该引用。于是代码演变如下:

class MyPromise {   constructor(executor) {     this.thencallback = null     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     this.thencallback(value)   }    _reject(value) { }    then(then_cb) {     this.thencallback = then_cb   } }

同理,继续演变,解决 catch 的执行问题。

class MyPromise {   constructor(executor) {     this.thencallback = null     this.rejectcallback = null     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     this.thencallback(value)   }    _reject(value) {     this.rejectcallback(value)   }    then(then_cb, onRejected) {     this.thencallback = then_cb     this.rejectcallback = onRejected   }    catch(onRejected) {     this.then(null, onRejected)   } }

如果不追求别的特性的话,我们的 Promise 对象就已经封装好,并且可以使用了。

写个例子简单验证一下

const p = new MyPromise((resolve, reject) => {   setTimeout(() => {     reject('异常信息')   }, 1000) })  p.then(res => {   console.log(res) })

完全符合预期。

然后简单调整,模拟将 then_cb 放入队列中执行,简单调整如下:

class MyPromise {   constructor(executor) {     this.thencallback = null     this.rejectcallback = null     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     setTimeout(() => {       this.thencallback(value)     }, 0)   }    _reject(value) {     setTimeout(() => {       this.rejectcallback(value)     }, 0)   }    then(then_cb, onRejected) {     this.thencallback = then_cb     this.rejectcallback = onRejected   }    catch(onRejected) {     this.then(null, onRejected)   } }

如果在面试中,被问到如何手写 Promise,实在想不起来,就把这段最简单的代码丢出去,基本上也能拿不错的高分啦。按照我的思路来想,十分简单。

将 Promise 的三种状态以及传递的值加入,让代码更规范一点

pending -> resolved

pending -> rejected

const pending = 'PENDING' const resolved = 'RESOLVED' const rejected = 'REJECTED'  class MyPromise2 {   constructor(executor) {     this.thencallback = undefined     this.rejectcallback = undefined     this._value = undefined     this._status = pending     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     if (!pending) return     this._status = resolved     this._value = value     setTimeout(() => {       this.thencallback(value)     }, 0)   }    _reject(value) {     if (!pending) return     this._status = rejected     this._value = rejected     setTimeout(() => {       this.rejectcallback(value)     }, 0)   }    then(then_cb, onRejected) {     this.thencallback = then_cb     console.log(then_cb)     this.rejectcallback = onRejected   }    catch(onRejected) {     this.then(null, onRejected)   } }  window.MyPromise2 = MyPromise2

then 可以多次调用,因此,缓存 then 的回调的引用,对应的应该是一个队列/数组。这样才能保证多次调用的 then_cb 都能执行。

因此,收集回调的 then 方法 与执行回调的 _resolve/_reject 都需要进行简单的调整

基于这个思路继续优化。

const pending = 'PENDING' const resolved = 'RESOLVED' const rejected = 'REJECTED'  const isFunction = (fn) => typeof fn === 'function'  class MyPromise2 {   constructor(executor) {     this.onResolvedQueue = []     this.onRejectedQueue = []     this._value = undefined     this._status = pending     executor(this._resolve.bind(this), this._reject.bind(this))   }    _resolve(value) {     if (!pending) return     const run = () => {       this._status = resolved       let cb;       // 执行队列中收集的回调,执行一个,删除一个,       // 队列思路:先进先出       while (cb = this.onResolvedQueue.shift()) {         this._value = value         cb(value)       }     }      setTimeout(run, 0)   }    _reject(value) {     if (!pending) return     const run = () => {       this._status = rejected       this._value = value       if (this.onRejectedQueue.length == 0) {         throw new Error(value)       }       let cb       while(cb = this.onRejectedQueue.shift()) {         cb(value)       }     }      setTimeout(run, 0)   }    then(onResolved, onRejected) {     // 根据不同的状态执行不同的逻辑     if (this._status === pending) {       if (isFunction(onResolved)) {         this.onResolvedQueue.push(onResolved)       }        if (isFunction(onRejected)) {         this.onRejectedQueue.push(onRejected)       }     }   }    catch(onRejected) {     this.then(null, onRejected)   } }  window.MyPromise2 = MyPromise2

验证一下,完美通过。
“`js
const p = new MyPromise2((resolve, reject) => {
setTimeout(() => {
resolve(‘xxx’)
}, 1000)
})

p.then(res => {
console.log(res)
})

p.then(res => {
console.log(‘2 then’, res)

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 六、6. Promise 的封装求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们