Open zhaoqize opened 6 years ago
这个文章,展现的是一个实现promise的思路,以及如何发现和处理问题的情境。
如果我们想要自己实现一个简单的Promise,那现有规范规定的Promise肯定是我们最好的参照。
Promise
我们先看下Promise怎么使用:
var promise1 = new Promise(function(resolve, reject){ // 成功后的TODO resolve(value); // 失败后的TODO reject(err); })
来看下返回的promise1是什么
promise1
再进行一些具体操作
var promise1 = new Promise(function(resolve, reject) { resolve('zqz') }) promise1.then(function(result) { console.log(result) }).catch(function(err){ console.log(err) }) // => 'zqz'
var promise1 = new Promise(function(resolve, reject) { reject('出现异常') }) promise1.then(function(result) { console.log(result) }).catch(function(err){ console.log(err) }) // => '出现异常'
从Promise的 使用方式上 和 实例 可以看到哪些东西:
reject
resolve
then
catch
PromiseStatus
PromiseValue
pending
fulfilled
rejected
根据上面的分析情况,我们先简单的来构造一个雏形。
function Promise(fn) { this.PromiseStatus = 'pending'; this.PromiseValue = ''; this.resolvedCb = []; this.rejectedCb = []; var self = this; var resolve = function (result) { // 判断状态 if (self.PromiseStatus === 'pending') { self.PromiseStatus = 'resolved'; self.PromiseValue = result; // resolvedCb 队列依次执行 for (var i = 0;i < self.resolvedCb.length; i++) { self.resolvedCb[i](result) } } } var reject = function (err) { // 判断状态 if (self.PromiseStatus === 'pending') { self.PromiseStatus = 'rejected'; self.PromiseValue = err; // rejectedCb 队列依次执行 for (var i = 0;i < self.rejectedCb.length; i++) { self.rejectedCb[i](result) } } } // 错误处理 -> rejected try { fn(resolve, reject) } catch(e) { reject(e) } }
当然这还不够,因为重要的两个功能then和catch还没有实现。
分析下then的使用
promise1.then(function(value){ // todo return value; }) .then(function(value1){ // todo return value1; }) .then(function(value2){ // todo return value2; })
return
根据Promise返回的实例,我们可看出来then是挂载在 Promise 的原型链上。
我们先实现一个大体的框架:
Promise.prototype.then = function (handleSuccess, handleFail) { var self = this; var PromiseStatus = this.PromiseStatus; if(typeof handleSuccess === 'function') { handleSuccess = handleSuccess; } else { handleSuccess = function (result) {} } if(typeof handleFail === 'function') { handleFail = handleFail; } else { handleFail = function (err) {} } if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { self.resolvedCb.push(handleSuccess); self.rejectedCb.push(handleFail); }) } if(PromiseStatus === 'resolved') { return new Promise(function(resolve, reject) { var result = handleSuccess(self.PromiseValue); resolve(result); }) } if(PromiseStatus === 'rejected') { return new Promise(function(resolve, reject) { var result = handleFail(self.PromiseValue); reject(result); }) } }
我们先用一下,看下是否符合期望
方式一(无异步操作):
function promise1() { return new Promise(function(resolve, reject){ console.log('执行promise1') resolve('zqz'); }) } promise1().then(function(result){ console.log('执行1', 'result:'+result) return result + '11'; }) .then(function(result){ console.log('执行2', 'result:'+result) return result + '22'; }) // => 执行promise1 // => 执行1 result:zqz // => 执行2 result:zqz11 // => Promise {PromiseStatus: "resolved", PromiseValue: "zqz1122", resolvedCb: Array(0), rejectedCb: Array(0)}
这样使用没有问题!
方式二(有异步操作):
function promise1() { return new Promise(function(resolve, reject){ // 异步操作 setTimeout(function(){ console.log('执行promise1') resolve('zqz'); },1000) }) } promise1().then(function(result){ console.log('执行1', 'result:'+result) return result + '11'; }) .then(function(result){ console.log('执行2', 'result:'+result) return result + '22'; }) // => 执行promise1 // => 执行1 result:zqz
一旦出现异步操作,就有问题!很明显,Promise的主要作用就是控制异步操作的执行顺序。
肯定是哪里有问题,我们来分析一下,异步的时候 有哪些 不同
在来看下我们在pending时候的处理
... // 异步时 if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { // 这里只是将函数塞入队列,然后就没有然后来。。。这是有问题的 self.resolvedCb.push(handleSuccess); self.rejectedCb.push(handleFail); }) } ...
这时候我们的两个数组:resolvedCb和rejectedCb就发挥作用了,由于我们不知道异步什么时候结束,但是我们可以根据他们定义的先后顺序注入到 队列 中,然后根据 顺序 依次执行,这样也就保证了异步操作的执行顺序。
resolvedCb
rejectedCb
队列
顺序
if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { // 一个个的塞入队列 self.resolvedCb.push(function(result) { var res = handleSuccess(self.PromiseValue); resolve(res); }) self.rejectedCb.push(function(err) { var er = handleFail(self.PromiseValue); reject(er); }) }) }
这时候我们用多个异步操作来测试一下
异步操作
function async1() { return new Promise(function(resolve, reject){ // 异步操作 setTimeout(function(){ console.log('执行async1') resolve('zqz1'); },3000) }) } function async2() { return new Promise(function(resolve, reject){ // 异步操作 setTimeout(function(){ console.log('执行async2') resolve('zqz2'); },1000) }) } function async3() { return new Promise(function(resolve, reject){ // 异步操作 setTimeout(function(){ console.log('执行async3') resolve('zqz3'); },2000) }) } // return 一个新的promise async1().then(function(result){ console.log('result = ' + result) return async2(); }).then(function(result){ console.log('result = ' + result) return async3(); }).then(function(result){ console.log('result = ' + result) return result; }) // => Promise {PromiseStatus: "pending", PromiseValue: "", resolvedCb: Array(0), rejectedCb: Array(0)} // => 执行async1 // => result = zqz1 // => result = [object Object] // => result = [object Object] // => 执行async2 // => 执行async3
这里有两个问题:
我们再来分析下,着重看下下面这块代码
... if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { self.resolvedCb.push(function(result) { // 这里返回的res有可能是promise,但是我们没有做处理 var res = handleSuccess(self.PromiseValue); resolve(res); }) self.rejectedCb.push(function(err) { // 这里返回的res有可能是promise,但是我们没有做处理 var er = handleFail(self.PromiseValue); reject(er); }) }) } ...
因为我们返回的是Promise,由于我们没有做处理,导致无法正确的获取到值。
... if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { self.resolvedCb.push(function(result) { var res = handleSuccess(self.PromiseValue); if (res instanceof Promise) { res.then(resolve, reject); } else { resolve(res); } }) self.rejectedCb.push(function(err) { var er = handleFail(self.PromiseValue); if (er instanceof Promise) { er.then(resolve, reject); } else { reject(er); } }) }) } ...
如果返回的是一个Promise,就继续塞入到then里面。
在执行一下:
async1().then(function(result){ console.log('result = ' + result) return async2(); }).then(function(result){ console.log('result = ' + result) return async3(); }).then(function(result){ console.log('result = ' + result) return result; }) // => Promise {PromiseStatus: "pending", PromiseValue: "", resolvedCb: Array(0), rejectedCb: Array(0)} // => 执行async1 // => result = zqz1 // => 执行async2 // => result = zqz2 // => 执行async3 // => result = zqz3
最后一个简单完整的 then:
Promise.prototype.then = function (handleSuccess, handleFail) { var self = this; var PromiseStatus = this.PromiseStatus; if(typeof handleSuccess === 'function') { handleSuccess = handleSuccess; } else { handleSuccess = function (result) {} } if(typeof handleFail === 'function') { handleFail = handleFail; } else { handleFail = function (err) {} } if(PromiseStatus === 'pending') { return new Promise(function(resolve, reject) { self.resolvedCb.push(function(result) { var res = handleSuccess(self.PromiseValue); if (res instanceof Promise) { res.then(resolve, reject); } else { resolve(er); } }) self.rejectedCb.push(function(err) { var er = handleFail(self.PromiseValue); if (er instanceof Promise) { er.then(resolve, reject); } else { reject(er); } }) }) } if(PromiseStatus === 'resolved') { return new Promise(function(resolve, reject) { var result = handleSuccess(self.PromiseValue); resolve(result); }) } if(PromiseStatus === 'rejected') { return new Promise(function(resolve, reject) { var result = handleFail(self.PromiseValue); reject(result); }) } }
参考
看完你的promise,感觉好牛逼呀! 简单大气,自己手敲一遍学习学习。
@wcx521 谢谢您的赞赏,互相学习!
写在前面
这个文章,展现的是一个实现promise的思路,以及如何发现和处理问题的情境。
从现有的Promise分析
如果我们想要自己实现一个简单的
Promise
,那现有规范规定的Promise
肯定是我们最好的参照。我们先看下
Promise
怎么使用:来看下返回的
promise1
是什么再进行一些具体操作
从Promise的 使用方式上 和 实例 可以看到哪些东西:
reject
和resolve
reject
和resolve
都有一个参数, 参数类型不限定then
和catch
,同时then可以有多个,所以需要一个回掉函数队列PromiseStatus
和PromiseValue
pending
,fulfilled
,rejected
根据上面的分析情况,我们先简单的来构造一个雏形。
当然这还不够,因为重要的两个功能
then
和catch
还没有实现。从现有的 then 分析
分析下
then
的使用return
的值 直接作为下个then
中匿名函数的入参根据Promise返回的实例,我们可看出来
then
是挂载在 Promise 的原型链上。我们先实现一个大体的框架:
我们先用一下,看下是否符合期望
方式一(无异步操作):
这样使用没有问题!
方式二(有异步操作):
一旦出现异步操作,就有问题!很明显,Promise的主要作用就是控制异步操作的执行顺序。
肯定是哪里有问题,我们来分析一下,异步的时候 有哪些 不同
PromiseStatus
是pending
状态在来看下我们在
pending
时候的处理这时候我们的两个数组:
resolvedCb
和rejectedCb
就发挥作用了,由于我们不知道异步什么时候结束,但是我们可以根据他们定义的先后顺序注入到队列
中,然后根据顺序
依次执行,这样也就保证了异步操作的执行顺序。这时候我们用多个
异步操作
来测试一下这里有两个问题:
我们再来分析下,着重看下下面这块代码
因为我们返回的是Promise,由于我们没有做处理,导致无法正确的获取到值。
如果返回的是一个Promise,就继续塞入到then里面。
在执行一下:
最后一个简单完整的 then:
参考