前言
不知道Promise是啥的,请看上一篇《异步流程控制》
看了不少Prmose实现的资料,目前的理解就是Promise也就是回调的一种优雅实现。
现在Javascript的重心都放在了async-await,而async-await是建立在Promise之上的,所以深入一下Promise,还是很有必要的。
实现功能分析
原生Promise
new Promise(function (resolve,reject){setTimeout(function (){console.log(1)resolve(2)},1000)}).then(function (val){setTimeout(function (){console.log('2:'+val)},1000)}).then(function (val){setTimeout(function (){console.log('3:'+val)},1000)})// 1// 2:2// 3:und
开始实现

创建一个_promise函数,由简到繁
简单功能
源码:
function _promise(fn){//resolve时的回调var callback;//一个实例的方法,用来注册异步事件this.then = function(done){callback = done;}function resolve(val){callback(val);}fn(resolve);}
使用:
new _promise(function (resolve){setTimeout(function (){console.log(1)resolve(2)},1000)}).then(function (val){setTimeout(function (){console.log('2:'+val)},1000)})// 1// 2:2
步骤分析:
- 传入fn执行,并调用then方法传入异步执行完毕后的函数赋值给Promise内部的callback
- Promise内部fn执行并将resolve函数作为参数传入
- fn执行到成功位置,执行resolve函数并传入成功值(val)
- resolve函数执行回调callback并传入成功值
链式支持
实现:
在then中返回this,并把then的回调存放到$resolve数组中,执行resolve使用forEach依次调用
function _promise(fn){// resolve时的回调var promise = this,value = null,promise.$resolve = [] // 存放需要调用的函数// 返回this,支持链式调用this.then = function (onFulfilled){promise.$resolve.push(onFulfilled)return this}// 成功回调,把$resolve存放的函数依次执行function resolve(value){promise.$resolve.forEach(function (callback){callback(value)})}fn(resolve)}
可是如果then中的传入函数是同步的话,就无法控制回调执行顺序
比如:
new _promise(function (resolve){for(var i = 0,num; i < 1000;i++){num=Math.random()*100}console.log(1)resolve(2)}}).then(function (val){setTimeout(function (){console.log('2:'+val)},1000)}).then(function (val){setTimeout(function (){console.log('3:'+val)},1000)})// 1
只会执行fn,回调都没有执行,因为这时在resolve比then先执行,这时候promise.$resolve数组是空数组,所以上面代码只打印了一个1。我们需要把resolve放到下一个任务队列末尾执行,也就是then的回调都添加到了数组中之后
修改resolve函数
function resolve(value){setTimeout(function (){promise.$resolve.forEach(function (callback){callback(value)})},0)}
引入状态
分析:
每个 Promise 存在三个互斥状态:pending、fulfilled、rejected。Promise 对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。
源码:
promise.value保存之后调用该对象回调的值
function _promise(fn){// 成功的回调var promise = thispromise.value = nullpromise.$resolve = [],promise.$status = 'PENDING'this.then = function (onFulfilled){if(promise.$status === 'PENDING'){promise.$resolve.push(onFulfilled)return this}onFulfilled(promise.value)return this}function resolve(value){setTimeout(function (){promise.$status = "FULFILLED";promise.$resolve.forEach(function (callback){callback(value)promise.value = value})},0)}fn(resolve)}
使用:
let a = new _promise(function (resolve){setTimeout(function (){console.log('1:')resolve(2)},1000)})a.then(function (val){console.log('2:'+val)})// 1// 2:2
异步回调返回的结果传递到下一个回调
修改resolve函数
function resolve(value){setTimeout(function (){promise.$status = "FULFILLED";promise.$resolve.forEach(function (callback){value = callback(value)promise.value = value})},0)}
失败处理
异步操作不可能都成功,在异步操作失败时,标记其状态为 rejected,并执行注册的失败回调。
有了之前处理 fulfilled 状态的经验,支持错误处理变得很容易。毫无疑问的是,在注册回调、处理状态变更上都要加入新的逻辑:
this.then = function (onFulfilled, onRejected){return new _promise(function (resolve){function handle(value){var ret = typeof onFulfilled === 'function' && onFulfilled(value) || value;resolve(ret)}function errback(reason){reason = typeof onRejected === 'function' && onRejected(reason) || reason;reject(reason)}if(promise.$status === 'PENDING'){promise.$resolves.push(handle)promise.$rejects.push(errback)} else if (promise.$status === 'FULFILLED') {handle(promise.$value)} else if (promise.$status === 'REJECTED') {errback(promise.$reason)}})}
