[JavaScript]一块儿来实现一个Promise

本文仅做为交流学习,主要为juejiner个人总结复习之用,还望大佬们轻喷

前言

初学js踩过最多的坑是什么,有人说是隐式转换,有人说是this改变,而对我而言,是异步函数。有不少次,被卡在空数据报错里,因而学会了默认值赋值,学会了深层判空,学会了经过异步回调来同步和异步加载数据或者控制状态的加载。javascript

而这里,不可避免的就要学习es6所推崇的promise异步编程方案。上一篇文章《[JavaScript] Promise 与 Ajax/Axios》中我简单介绍了promise的用法。那么这里咱们来深延一下promise,看看这方神圣到底能玩出什么❀来~html

一 Promise

开始研究以前除了看看阮神的es6,红皮书,和掘友的文章以外,固然得看看比较官方的实现以及相关规范了java

promise-polyfill
react

PromiseA+ios

whatgit

一个构造函数,其参数为一个excutor,其构造出的对象拥有私有成员state,value,reactios...etces6

下面是一个简单的Promise,不用细看扫一眼往下走接着看介绍github

// 格式挂了...
function Promise (excutor) {
 let _ = this
 _.state = 'pending'
 _.value = undefined
 _.fullfillArr = []
 _.rejectedArr = []
 let resolve = result => {
   if (this.state !== 'pending') return
   setTimeout(() => {
     this.state = 'fullfilled'
     this.value = result
     this.fullfillArr.forEach(fn => {
      fn()
     })
   }, 0)
 }
 let reject = reason => {
   if (this.state !== 'pending') return
   setTimeout(() => { // 同步时插入,保证回调函数被异步执行
     this.state = 'rejected'
     this.value = reason
     this.rejectedArr.forEach(fn => {
       fn()
    })
   }, 0)
 }
 try {
   excutor(resolve, reject)
 } catch (error) {
   reject(error)
 }
}   

能够看到Promise中有编程

1.1 几个私有成员

state数组

中存储状态值,有三种,实例化时的'pending',被resolve或reject函数调用时被决定为fullfilled或rejected。

value

中存储状态改变函数resolvet所传过来的值。

reason

中存储状态改变函数reject所传来的值。

1.2 执行器函数excutor

主要做用是进行一些同步异步操做而后在异步的回调函数中调用状态改变函数,或者是同步结束时调用状态改变函数。固然你也能够啥都不调用,这样也就没有后续被添进callbackArray中的大伙们啥事了。

excutor为Promise的形参,其实参为new Promise((resolve, reject) => { resolve(233) })中的(resolve, reject) => { resolve(233) },即一个定制的函数。

该函数有两个参数: resolve, reject,两个形参在excutor被调用时实参分别对应Promise的内部函数resolve, reject。

而resolve和reject内部函数且看下面

1.3 执行器函数的两个参数

是两个函数,做用是在将须要改变promise对象状态时将其状态改变,而且传入一个所需的值赋值给promiseX.value。

在promise的excutor中被执行时的两个参数被传入Promise内部函数resolve, reject,在被调用时实参为其传来的值,如上栗中的233。

好了看完这些,你大概知道Promise和他的执行器都在干吗了,大概核心就是实例化一个对象,该对象拥有几个拥有默认值的私有成员:状态,值...等等,而后再执行一下excutor执行器函数,这个时候根据需求将对象的状态值决定下来而且将某个传来的值保存下来。

好了,大致就作了这些,那么作了这些才只是开始呀,咱们用Promise不就是想代替回调地狱吗,链式调用的时候怎么实现,值怎么传过去,何时执行定义好的下一个步骤,这些看下一节核心方法:then的实现。

二 Promise.prototype.then

then是干吗的? 指定promise对象在决定态(onFullfilled, onRejected)时多执行的回调函数

因此then是一个函数,其形参有两个,onFullfilled ,onRejected,第二个参数为可选。其实参为咱们实际定制时所定义的函数。

eg:

new Promise((resolve, reject) => {
 resolve('fullfilled')
})
.then(
(res) => {console.log(res)},
(reason) => {coonsole.log(reason)}
)复制代码

上个栗子中的(res) => {console.log(res)}即为onFullfilled对应的实参, (reason) => {coonsole.log(reason)}即为onRejected对应的实参。它只是个函数的引用,因此不要看着一大串就觉得在执行,实际上这两个函数并无在上述的同步代码中执行,为何呢,看下面

2.1 异步执行与同步then

为了可以使同一个promise在状态决定后去同步执行多个步骤,好比A动画完了后要求加载B,C动画,且BC动画由于其后续场景不一样的缘由不该该放置一个函数中,那么就有了一个promise屡次,then同步执行的需求了。则异步执行就很重要了,须要在本次栈内代码执行完多个then添加后再去进行状态更改而且将该promise下的then所有执行。啧啧,发布订阅的感受吼。不同的是,错事后该次改变后再添加一样能获得执行。

本文里使用了setTimeout异步宏任务来实现异步,从而使状态值更改时全部的then回调都已经添加到位从而被所有执行。

同时,promise对象中要有两个回调函数数组fufillArr,rejectArr来储存每一个then中的onfullFilled和onRejected,其添加(push)时机固然是在then函数中了。这里就对应了本节第一句主题:指定promise对象在决定态(onFullfilled, onRejected)时多执行的回调函数。

2.2 then的链式

写以前不妨先想一想,链式什么意思,不就是在回调中再去调用一个回调的意思吗,那么在异步回调需求出现时,咱们不就又须要一个状态机器Promise了么,立刻给他来个return new Promise(....)操做。ok,这不就完事了。个锤子了。

好了你有了promise对象返回知道怎么决定后续的状态了,那你还么得作上面的要求push呢,因而咱们将push操做放在了这个要new 的Peomise的excutor中,这样的意义在于后续的回调决定于前一轮push进去的回调的执行结果。

到这里,一个简易的promise以及then的实现过程就说的差很少了固然中间又不少判断以及普通值状况判断就不细说了一切皆在代码中,那么上一下then 的代码。

// 格式又挂了,直接看下面github上代码吧 
Promise.prototype.then = function (onfullFilled, onRejected) {                                 typeof onfullFilled !== 'function' ? onfullFilled = result => result : null;            typeof onRejected !== 'function' ? onRejected = reason => {                throw new Error(reason instanceof Error ? reason.message : reason);            } : null                                         return new Promise((resolve, reject) => {                                                this.fullfillArr.push(() => {                    try {                        let onfullFilledReturn = onfullFilled(this.value)                                                onfullFilledReturn instanceof Promise ? onfullFilledReturn.then(resolve, reject) : resolve(onfullFilledReturn)                    } catch (error) {                        reject(error)                    }                })                                                                       this.rejectedArr.push(() => {                    try {                        let onRejectedReturn = onRejected(this.value)                        onRejectedReturn instanceof Promise ? onRejectedReturn.then(resolve, reject) : resolve(onRejectedReturn)                    } catch (error) {                        reject(error)                    }                })                            })      }复制代码

最后挂一下总体的实现以及验证连接: promiseComeTrue.html

三 Promise.prototype.all and Promise.prototype.race

也是写实现,不是很难,你们本身写下吧,我明天再写。困。。

参考

Promise 对象

promise-polyfill

PromiseA+

我如何实现Promise A+

扒一扒PROMISE的原理,你们不要怕!

Promise原理讲解 && 实现一个Promise对象 (遵循Promise/A+规范)

相关文章
相关标签/搜索