手写一个promise用法_【原】手写一个promise

上一篇文章中,我们介绍了Promise的基本使用,在这篇文章中,我们试着自己来写一个Promise,主要是学习Promise的内部机制,学习它的编程思想。

!!!备注:本文写的不好,仅供自己学习之用,具体的实现过程建议看下面的参考文章。所以本文没有发布到博客园首页和其他地方

Promise API分析

正常使用方法

我们来看一个正常的使用:

var p=new Promise(function(resolve,rejcet){

setTimeout(function(){if(true){

resolve('success');

}else{

rejcet('failure');

}

},1000);

});

p.then(function(value){

console.log(value);

},function(error){

console.log(error);

});//success

接下来我们就来实现这么一个Promise.

先来了解相关的一些术语:

解决(fulfill):指一个 promise 成功时进行的一系列操作,如状态的改变、回调的执行。虽然规范中用 fulfill 来表示解决,但在后世的 promise 实现多以 resolve 来指代之。

拒绝(reject):指一个 promise 失败时进行的一系列操作。

终值(eventual value):所谓终值,指的是 promise 被解决时传递给解决回调的值,由于 promise 有一次性的特征,因此当这个值被传递时,标志着 promise 等待态的结束,故称之终值,有时也直接简称为值(value)。

据因(reason):也就是拒绝原因,指在 promise 被拒绝时传递给拒绝回调的值。

Promise的流程图分析

promise的执行流程如如下:

Promise链式操作中,执行顺序是如何保证的

每个promise后面链一个对象该对象包含onfulfiled,onrejected,子promise三个属性,当父promise 状态改变完毕,执行完相应的onfulfiled/onfulfiled的时候呢,拿到子promise,在等待这个子promise状态改变,再执行相应的onfulfiled/onfulfiled。依次循环直到当前promise没有子promise

如何让异步的value在thenable函数中拿到

将resolve/reject函数和onfulfiled/onrejected放入同一个对象(promise对象)里面,resolve/reject的时候将value设置this.value=xxx。onfulfiled/onrejected执行的时候呢,onfulfiled(this.value)即可。

在这里避免头晕,解释一下,onfulfilled和onrejected指的是then里面的两个函数。

状态机制切换

如图所示,状态只能由pengding-->fulfilled,或者由pending-->rejected这样转变。

只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

开始手写Promise

1、 首先我们来写好我们的框架

ES6原生的构建方式为:

// Promise构造函数接收一个executor函数,executor函数执行完同步或异步操作后,调用它的两个参数resolve和reject

var promise = new Promise(function(resolve, reject) {

/*

如果操作成功,调用resolve并传入value

如果操作失败,调用reject并传入reason

*/

})

我们就按照这种方式来搭好框架

functionPromise(callback) {var self = thisself.status= 'PENDING' //Promise当前的状态

self.data = undefined //Promise的值

self.onResolvedCallback = [] //Promise resolve时的回调函数集

self.onRejectedCallback = [] //Promise reject时的回调函数集

callback(resolve, reject) //执行executor并传入相应的参数

functionresolve(value){

}functionrejecte(error){

}

}//添加我们的then方法

Promise.prototype.then=function(){

}

我们构造一个Promise函数,并传入一个回调callback,callback里面传入两个函数作为参数,一个是resove,一个是reject。并在Promise的原型上加入我们的then方法。

2、完善框架里面的内容

框架搭好了,接下来我们来一点点的完善框架里面的内容,可以这么说,把resolve,reject和then补充完,基本可以说就是把Promise完成了。

我们先来完善我们的resolve和rejected:

functionPromise(callback) {var self = thisself.status= 'PENDING' //Promise当前的状态

self.data = undefined //Promise的值

self.onResolvedCallback = [] //Promise resolve时的回调函数集

self.onRejectedCallback = [] //Promise reject时的回调函数集

callback(resolve, reject) //执行executor并传入相应的参数

functionresolve(value){if(self.status=='PENDING'){

self.status=='FULFILLED';

self.data=value;//依次执行成功之后的函数栈

for(var i = 0; i < self.onResolvedCallback.length; i++) {

self.onResolvedCallback[i](value)

}

}

}functionrejecte(error){if (self.status === 'PENDING') {

self.status= 'REJECTED'self.data=error;//依次执行失败之后的函数栈

for(var i = 0; i < self.onRejectedCallback.length; i++) {

self.onRejectedCallback[i](error)

}

}

}

}

如果是penging,则改变相应的状态,并把resolve和reject的值保存子data里面。

接下来我们实现我们的then方法:

then方法是Promise的核心,因此这里会花比较大的篇幅去介绍then:

一个promise的then接受两个参数:

promise.then(onFulfilled, onRejected)

onFulfilled 和 onRejected 都是可选参数。

如果 onFulfilled 不是函数,其必须被忽略

如果 onRejected 不是函数,其必须被忽略

onFulfilled 特性

如果 onFulfilled 是函数:

当 promise 执行结束后其必须被调用,其第一个参数为 promise 的终值,也就是resolve传过来的值

在 promise 执行结束前其不可被调用

其调用次数不可超过一次

onRejected 特性

如果 onRejected 是函数:

当 promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的据因,也就是reject传过来的值

在 promise 被拒绝执行前其不可被调用

其调用次数不可超过一次

调用时机

onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用(平台代码指引擎、环境以及 promise 的实施代码)

调用要求

onFulfilled 和 onRejected 必须被作为函数调用(即没有 this 值,在 严格模式(strict) 中,函数 this 的值为 undefined ;在非严格模式中其为全局对象。)

多次调用

then 方法可以被同一个 promise 调用多次

当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调

当 promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调

返回

then 方法必须返回一个 promise 对象

promise2 = promise1.then(onFulfilled, onRejected);

如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)

如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e

如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值

如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因

不论 promise1 被 reject 还是被 resolve 时 promise2 都会被 resolve,只有出现异常时才会被 rejected。

每个Promise对象都可以在其上多次调用then方法,而每次调用then返回的Promise的状态取决于那一次调用then时传入参数的返回值,所以then不能返回this,因为then每次返回的Promise的结果都有可能不同。

接下来我们来写我们的then方法:

Promise.prototype.then= function(onResolved, onRejected) {var self = this

varpromise2//根据标准,如果then的参数不是function,则我们需要忽略它,此处以如下方式处理

onResolved = typeof onResolved === 'function' ? onResolved : function(value) {}

onRejected= typeof onRejected === 'function' ? onRejected : function(reason) {}if (self.status === 'resolved') {//如果promise1(此处即为this/self)的状态已经确定并且是resolved,我们调用onResolved

//因为考虑到有可能throw,所以我们将其包在try/catch块里

return promise2 = new Promise(function(resolve, reject) {try{var x =onResolved(self.data)if (x instanceof Promise) { //如果onResolved的返回值是一个Promise对象,直接取它的结果做为promise2的结果

x.then(resolve, reject)

}

resolve(x)//否则,以它的返回值做为promise2的结果

} catch(e) {

reject(e)//如果出错,以捕获到的错误做为promise2的结果

}

})

}//此处与前一个if块的逻辑几乎相同,区别在于所调用的是onRejected函数,就不再做过多解释

if (self.status === 'rejected') {return promise2 = new Promise(function(resolve, reject) {try{var x =onRejected(self.data)if (x instanceofPromise) {

x.then(resolve, reject)

}

}catch(e) {

reject(e)

}

})

}if (self.status === 'pending') {//如果当前的Promise还处于pending状态,我们并不能确定调用onResolved还是onRejected,

//只能等到Promise的状态确定后,才能确实如何处理。

//所以我们需要把我们的**两种情况**的处理逻辑做为callback放入promise1(此处即this/self)的回调数组里

//逻辑本身跟第一个if块内的几乎一致,此处不做过多解释

return promise2 = new Promise(function(resolve, reject) {

self.onResolvedCallback.push(function(value) {try{var x =onResolved(self.data)if (x instanceofPromise) {

x.then(resolve, reject)

}

}catch(e) {

reject(e)

}

})

self.onRejectedCallback.push(function(reason) {try{var x =onRejected(self.data)if (x instanceofPromise) {

x.then(resolve, reject)

}

}catch(e) {

reject(e)

}

})

})

}

}//为了下文方便,我们顺便实现一个catch方法

Promise.prototype.catch = function(onRejected) {return this.then(null, onRejected)

}

完整代码如下:

try{

module.exports=Promise

}catch(e) {}functionPromise(executor) {var self = thisself.status= 'pending'self.onResolvedCallback=[]

self.onRejectedCallback=[]functionresolve(value) {if (value instanceofPromise) {returnvalue.then(resolve, reject)

}

setTimeout(function() { //异步执行所有的回调函数

if (self.status === 'pending') {

self.status= 'resolved'self.data=valuefor (var i = 0; i < self.onResolvedCallback.length; i++) {

self.onResolvedCallback[i](value)

}

}

})

}functionreject(reason) {

setTimeout(function() { //异步执行所有的回调函数

if (self.status === 'pending') {

self.status= 'rejected'self.data=reasonfor (var i = 0; i < self.onRejectedCallback.length; i++) {

self.onRejectedCallback[i](reason)

}

}

})

}try{

executor(resolve, reject)

}catch(reason) {

reject(reason)

}

}functionresolvePromise(promise2, x, resolve, reject) {varthenvar thenCalledOrThrow = false

if (promise2 ===x) {return reject(new TypeError('Chaining cycle detected for promise!'))

}if (x instanceofPromise) {if (x.status === 'pending') { //because x could resolved by a Promise Object

x.then(function(v) {

resolvePromise(promise2, v, resolve, reject)

}, reject)

}else { //but if it is resolved, it will never resolved by a Promise Object but a static value;

x.then(resolve, reject)

}return}if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {try{

then= x.then //because x.then could be a getter

if (typeof then === 'function') {

then.call(x,functionrs(y) {if (thenCalledOrThrow) returnthenCalledOrThrow= true

returnresolvePromise(promise2, y, resolve, reject)

},functionrj(r) {if (thenCalledOrThrow) returnthenCalledOrThrow= true

returnreject(r)

})

}else{

resolve(x)

}

}catch(e) {if (thenCalledOrThrow) returnthenCalledOrThrow= true

returnreject(e)

}

}else{

resolve(x)

}

}

Promise.prototype.then= function(onResolved, onRejected) {var self = this

varpromise2

onResolved= typeof onResolved === 'function' ? onResolved : function(v) {returnv

}

onRejected= typeof onRejected === 'function' ? onRejected : function(r) {throwr

}if (self.status === 'resolved') {return promise2 = new Promise(function(resolve, reject) {

setTimeout(function() { //异步执行onResolved

try{var x =onResolved(self.data)

resolvePromise(promise2, x, resolve, reject)

}catch(reason) {

reject(reason)

}

})

})

}if (self.status === 'rejected') {return promise2 = new Promise(function(resolve, reject) {

setTimeout(function() { //异步执行onRejected

try{var x =onRejected(self.data)

resolvePromise(promise2, x, resolve, reject)

}catch(reason) {

reject(reason)

}

})

})

}if (self.status === 'pending') {//这里之所以没有异步执行,是因为这些函数必然会被resolve或reject调用,而resolve或reject函数里的内容已是异步执行,构造函数里的定义

return promise2 = new Promise(function(resolve, reject) {

self.onResolvedCallback.push(function(value) {try{var x =onResolved(value)

resolvePromise(promise2, x, resolve, reject)

}catch(r) {

reject(r)

}

})

self.onRejectedCallback.push(function(reason) {try{var x =onRejected(reason)

resolvePromise(promise2, x, resolve, reject)

}catch(r) {

reject(r)

}

})

})

}

}

Promise.prototype.catch = function(onRejected) {return this.then(null, onRejected)

}

Promise.deferred= Promise.defer = function() {var dfd ={}

dfd.promise= new Promise(function(resolve, reject) {

dfd.resolve=resolve

dfd.reject=reject

})returndfd

}

View Code

本文没有写好,有点头晕,所以具体的实现过程还是建议看下面的参考文章。

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值