这篇“JavaScript怎么实现简易的Promise对象”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JavaScript怎么实现简易的Promise对象”文章吧。
实现一个简易的Promise对象,我们首先要了解几个相关的知识点:
Promise对象的状态: pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
Promise的参数: Promise构造函数接收一个函数作为参数,函数内部有两个参数,分别是resolve和reject,这两个参数是两个函数,由JS引擎提供,不需要我们部署。reslove函数
的作用是将Promise对象的状态由 'pending' 状态变为 'resolved'状态即('fulfilled'状态),方便与参数名对应,reject函数
的作用是将Promise对象的状态由 'pending' 状态变为 'rejected'状态。
但是我们应该注意的是,Promise对象的状态一经改变,就不再发生改变(即pending
--> resolved
|| pending
--> rejected
其中任意一种发生改变之后,Promise对象的状态将不再发生改变)
let p1 = new Promise((resolve, reject) => { resolve('成功'); reject('失败'); throw('报错'); //相当于reject() }) console.log(p1);
让我们看看三种状态的打印的结果分别是什么吧
class myPromise { constructor(executor) { this.status = 'pending'; // 变更promise的状态 this.value = null; executor(this.resolve, this.reject); // new 一个myPromise 得到的实例对象里面有两个函数 } resolve(value) { if (this.status !== 'pending') return; this.status = 'fulfilled'; // 变更promise的状态 this.value = value; } reject(reason) { if (this.status !== 'pending') return this.status = 'rejected'; this.value = reason; } }
貌似这么写代码逻辑也说得通,那么让我们看一下实现的效果:
看到这里,不难想到我们的resolve和reject的两个方法的this
指向出现了问题,我们仔细看看不难发现,这两个方法被我们作为实参放到了构造器函数,此时this的指向是指向了构造器函数,而不是我们写的myPromise这个构造函数身上,那只需要bind
显示绑定一下this 的指向就可以解决了。
executor(this.resolve.bind(this), this.reject.bind(this))
并且myPromise的状态一经变更也不再改变,是不是有一点原装Promise的味道了。但是在Promise里面还有一个错误捕捉机制,只要promise里面执行的逻辑报错了,就需要走reject逻辑,将错误抛出来,那我们只需要使用try catch来实现就可以。
try { executor(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { this.reject(error) }
这样我们就实现了极简版的Promise对象,但是通常情况下我们都是使用Promise对象来处理异步的问题,说到异步,那不得不提起Promise.prototype.then()
这个方法了,then
方法返回的是一个新的Promise实例
(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
then方法的第一个参数是`resolved状态的回调函数`,第二个参数是`rejected状态的回调函数`,它们都是可选的。
当promise的状态为'fulfilled'会执行第一个回调函数,当状态为'rejected'时执行第二个回调函数。
必须等到Promise的状态变更过一次之后,状态为'fulfilled'或者'rejected',才去执行then里面的逻辑。
.then支持链式调用,下一次.then受上一次.then执行结果的影响。
知道以上这几点,我们就可以尝试如何实现.then方法了
class myPromise { constructor(executor) { this.status = 'pending'; this.value = null; this.onFulfilledCallbacks = []; // 用来保存成功的回调(处理异步) this.onRejectedCallbacks = []; // 用来保存失败的回调(处理异步) try { executor(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { this.reject(error) } } resolve(value) { if (this.status !== 'pending') return; this.status = 'fulfilled'; this.value = value; // 调用then里面的回调 while (this.onFulfilledCallbacks.length) { // 当异步成功回调数组中存在回调函数,那就执行 this.onFulfilledCallbacks.shift()(this.value) } } reject(reason) { if (this.status !== 'pending') return this.status = 'rejected'; this.value = reason; while (this.onRejectedCallbacks.length) { // 当异步失败回调数组中存在回调函数,那就执行 this.onRejectedCallbacks.shift()(this.value) } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val // 判断.then的第一个参数是不是一个函数,如果不是就直接作为结果返回 onRejected = typeof onRejected === 'function' ? onRejected : val => { throw val } // 判断.then的第二个参数是不是一个函数,如果不是就直接作为错误返回 var thenPromise = new myPromise((resolve, reject) => { // 因为.then返回的是一个心的Promise对象 const resolvePromise = callback => { // 用于判断回调函数的类型 setTimeout(() => { // 让整个回调函数比同步代码晚一点执行,官方不是使用setTimeout实现 try { const x = callback(this.value); if (x === thenPromise) { // 你正在返回自身 throw new Error('不允许返回自身!'); } if (x instanceof myPromise) { // 返回的是一个Promise对象 x.then(resolve, reject); } else { // 直接返回一个值,作为resolve的值,传递给下一个.then resolve(x); } } catch (error) { reject(error); throw new Error(error) } }) } if (this.status === 'fulfilled') { resolvePromise(onFulfilled) } else if (this.status === 'rejected') { resolvePromise(onRejected) } else if (this.status === 'pending') { this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled)); this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected)); } }) return thenPromise } }
以上就是关于“JavaScript怎么实现简易的Promise对象”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。