JS之手写Promise
2021-02-01 11:15
-
准备
(1)
status
记录Promise
的状态,初始值为pendding
状态就是正在进行。(2)
data
记录Promise
返回的数据。(3)
callbacks
,这是一个数组,用来记录需要执行的回调函数队列,里面存储了成功和失败的回调。(4)
Promise
的参数为一个函数(构造器),函数里面又有两个函数调用,好了,了解清楚之后我们就可以开始写Promise
的结构了。向外暴露Promise:
;(function (window) { function Promise(executor){} window.Promise = Promise })(window)
-
构造器部分
既然构造器中有两个可执行函数,那么我们就要实现这两个函数。其实两个函数都是差不多的结构只是状态不同,执行的回调函数不同。那么实现我们上边说了,需要有三种状态,那么我们就需要进行定义,而且还需要定义执行的回调函数队列,并且需要有一个变量来存储存储返回的数据,那么思路捋清楚了就可以开始了:
/** * @param {Function} executor 执行器 * @return {Promise} A new instance of Promise * when catch error set promise.status to rejected */ function Promise(executor) { const self = this self.status = PENDING self.data = null self.callbacks = [] function resolve(value) { // 状态只能改变一次 if (self.status !== PENDING) { return } self.status = RESOLVED self.data = value if (self.callbacks.length > 0) { setTimeout(() => { self.callbacks.forEach((callbacksObj) => { callbacksObj.onResolved(value) }) }) } } function reject(reason) { if (self.status !== PENDING) { return } self.data = reason self.status = REJECTED if (self.callbacks.length > 0) { setTimeout(() => { self.callbacks.forEach((callbacksObj) => { callbacksObj.onRejected(reason) }) }) } } try { executor(resolve, reject) } catch (error) { reject(error) } }
-
then
方法实现:3.1
then
方法中也有两个回调函数,一个成功的回调,一个失败的回调,并且需要返回一个新的Promise
,这就是为什么Promise
可以链式调用的原因。写之前先捋一下逻辑,首先需要判断传入的是否为回调函数,如果为回调那么执行回调,如果成功回调为基本类型的值,那么次promise
就直接变为成功状态,若为失败那么直接向下抛出异常值。then(onResolved, onRejected) { onRejected = typeof === ‘function‘ ? onRejected : value => value // 否则拿到value值构造一个函数赋值给成功参数 onRejected = typeof === ‘function‘ ? onRejected : reason => { throw reason } // 否则变为一个向下抛出错误的异常函数 const self = this // 老样子保存引用 return new Promise((resolve, reject) => { if(self.status === PENDING) { // pending状态我们将回调推入回调函数队列 self.callbacks.push({ OnResolved(value){}, // 回调里的操作决定了Promise的状态,所以还需要进行验证 onRejected(reason){} }) } } ) }
3.2
then方法第二部分(解决回调函数内容)
/* 返回promise的结果由onResolved/onRejected执行结果决定 1. 抛出异常, 返回promise的结果为失败, reason为异常 2. 返回的是promise, 返回promise的结果就是这个结果 3. 返回的不是promise, 返回promise为成功, value就是返回值 */
所以我们需要一个
handler
函数来帮助我们判断回调函数的处理结果,之后才执行相应处理。?
function handler(callback) { /* 返回promise的结果由onResolved/onRejected执行结果决定 1. 抛出异常, 返回promise的结果为失败, reason为异常 2. 返回的是promise, 返回promise的结果就是这个结果 3. 返回的不是promise, 返回promise为成功, value就是返回值 */ try { const result = callback(self.data) if (result instanceof Promise) { result.then(resolve, reject) } else { resolve(result) } } catch (error) { reject(error) } }
3.3
then方法第三部分(完善then)
Promise.prototype.then = function (onResolved, onRejected) { const self = this // 给参数赋予默认值,默认的函数 onResolved = typeof onResolved === ‘function‘ ? onResolved : (value) => value onRejected = typeof onRejected === ‘function‘ ? onRejected : (reason) => { throw reason } // 返回一个 promise return new Promise((resolve, reject) => { // 定义 handler函数,处理回调函数(利用闭包) function handler(callback) { /* 返回promise的结果由onResolved/onRejected执行结果决定 1. 抛出异常, 返回promise的结果为失败, reason为异常 2. 返回的是promise, 返回promise的结果就是这个结果 3. 返回的不是promise, 返回promise为成功, value就是返回值 */ try { const result = callback(self.data) if (result instanceof Promise) { result.then(resolve, reject) } else { resolve(result) } } catch (error) { reject(error) } } if (self.status === RESOLVED) { // status 为 resolved 加入异步回调队列 setTimeout(() => { handler(onResolved) }) } else if (self.status === REJECTED) { // status 为 rejected 加入异步回调队列 setTimeout(() => { handler(onRejected) }) } else { // status 为 pending 装入回调数组 self.callbacks.push({ onResolved() { // 改变状态 handler(onResolved) }, onRejected() { handler(onRejected) }, }) } }) }
-
catch
方法catch
方法比较简单就是捕获错误,那么我们就可以直接复用then
方法。Promise.prototype.catch = function (onRejected) { return this.then(null, onRejected) }
-
resolve
方法返回一个 Promise对象,其实是一个语法糖
Promise.resolve = function (value) { return new Promise((resolve, reject) => { if (value instanceof Promise) { value.then(resolve, reject) } else { resolve(value) } }) }
-
reject
方法类似:
Promise.reject = function (reason) { return new Promise((resolve, reject) => { reject(reason) }) }
-
all
和race
方法all
方法接受一个数组,数组中的数据为Promise
多个实例,也可以是基本类型的值,当数组中的多个Promise
的状态全都成功时,这个返回值才是成功值,,否则失败。需要补充的是all
方法的成功返回值的顺序与数组中实例顺序是对应的关系。race
方法的参数也是一个数组,数组中也是一个个promise
实例,但是这个方法返回的值并不是数组,而是哪个promise
率先执行完毕,那么此promise
的状态值就为这个promise
的状态值,听起来可能有点绕哈,下面开始代码的实现:/** * @param {[Promise]} promises The Array of promise * @return {Promise} A new promise */ Promise.all = function (promises) { const values = new Array(promises.length) // 保存结果 let resolvedCount = 0 // 统计resolved的Promise个数 return new Promise((resolve, reject) => { promises.forEach((p, index) => { Promise.resolve(p).then( (value) => { resolvedCount += 1 values[index] = value if (resolvedCount === promises.length) { resolve(values) } }, (reason) => { reject(reason) } ) }) }) } /** * @param {[Promise]} promises The Array of promise * @return {Promise} A new promise */ Promise.race = function (promises) { return new Promise((resolve, reject) => { promises.forEach((p) => { Promise.resolve(p).then( (value) => { resolve(value) }, (reason) => { reject(reason) } ) }) }) }
完整代码
项目的完整代码