上一篇文章【实现简易 ES6 Promise 功能 (一)】实现了基本的异步功能。今天我们接着上次的内容继续扯,如何实现【数据传递】以及当【回调函数返回一个新的promise】
上篇已完成的代码
function Promise(func){
this.state = 'pending';
this.doneList = [];
func(this.resolve.bind(this));
}
Promise.prototype = {
resolve: function(){
while(true){
if( this.doneList.length === 0 ){
this.state = 'done';
break;
}
this.doneList.shift().apply(this);
}
},
then: function(callback){
this.doneList.push(callback);
if( this.state === 'done'){
this.state = 'pending';
this.resolve();
}
return this;
}
}
测试代码
new Promise(function(resolve){
resolve(1)
}).then(function(data){
console.log(data); // 1
return 2;
}).then(function(data){
console.log(data); // 2
});
上面的结果,就是我们要实现的。resolve的参数(只传递第一个参数,如果有)传递给第一个then里面函数作为参数,第一个then里面的函数返回值传递给第二个then里面的函数作为参数,以此类推。
关键代码
resolve: function(){
// arguments[0]是resolve的第一个参数
while(true){
if( this.doneList.length === 0 ){
this.state = 'done';
break;
}
// 这里是运行then里面回调函数的地方
this.doneList.shift().apply(this);
}
}
如何修改呢?除了第一次传递参数,是把resolve的参数往下传递,其余的都是把上次的结果作为下次开始(参数)。
于是,我们可以先把上次doneList里面的函数运行结果保存起来。然后,等到下次需要的时候,再传给下一个回调函数。
代码修改:
resolve: function(){
// arguments[0]是resolve的第一个参数
var arg = arguments[0];
while(true){
if( this.doneList.length === 0 ){
this.state = 'done';
break;
}
// 这里是运行then里面回调函数的地方
// 以数组形式传给下一个函数,然后保存新的值
// 判断传递的参数是否为undefined,是的话,就不用传了
if( typeof arg === 'undefined' ){
arg = this.doneList.shift().apply(this);
}else{
arg = this.doneList.shift().apply(this, [arg]);
}
}
// 保存最后的arg,保证后续的回调能继续得到参数
this.arg = arg;
}
// 还需要修改then方法
then: function(callback){
this.doneList.push(callback);
if( this.state === 'done'){
this.state = 'pending';
this.resolve(this.arg); // 注意这里也要传递参数
}
return this;
}
第一次修改完善的代码,及测试结果
function Promise(func){
this.state = 'pending';
this.doneList = [];
func(this.resolve.bind(this));
}
Promise.prototype = {
resolve: function(){
// arguments[0]是resolve的第一个参数
var arg = arguments[0];
while(true){
if( this.doneList.length === 0 ){
this.state = 'done';
break;
}
// 这里是运行then里面回调函数的地方
// 以数组形式传给下一个函数,然后保存新的值
// 判断传递的参数是否为undefined,是的话,就不用传了
if( typeof arg === 'undefined' ){
arg = this.doneList.shift().apply(this);
}else{
arg = this.doneList.shift().apply(this, [arg]);
}
}
// 保存最后的arg,保证后续的回调能继续得到参数
this.arg = arg;
},
then: function(callback){
this.doneList.push(callback);
if( this.state === 'done'){
this.state = 'pending';
this.resolve(this.arg); // 注意这里也要传递参数
}
return this;
}
}
// 测试
new Promise(function(resolve){
resolve(1)
}).then(function(data){
console.log(data); // 1
return 2;
}).then(function(data){
console.log(data); // 2
});
结果截图:
今天的第一个功能已经完了,那么现在开始开发第二个功能。
先看一个测试
new Promise(function(resolve){
resolve(1)
}).then(function(data){
console.log(data, 2); // 1,2
return new Promise(function(resolve){
window.setTimeout(function(){
resolve(3);
}, 1000);
}).then(function(data){
console.log(data, 4); // 3,4
return 5;
});
}).then(function(data){
console.log(data, 6); // 5, 6
});
测试结果
我在上面测试例子中,then回调函数中返回的promise中故意使用了延迟函数。但是,输出结果中5往后传了,并且[5,6]是在[3,4]之后,且都有一秒中的延迟。
如果没有回调返回一个promise,程序会一直按照第一行走下去,就算回调中有其他promise(只要不return),也是两条并行的线。一旦返回promise,新的promise会在这个点插入,并且原来还没有执行的回调,也会排到新的回调列表后面了。
先来修改resolve方法,因为回调函数都是在这里运行的。
resolve: function(){
// arguments[0]是resolve的第一个参数
var arg = arguments[0];
while(true){
if( this.doneList.length === 0 ){
this.state = 'done';
break;
}
/*************************/
if( arg instanceof Promise ){
// 把新的promise保存起来,待会要用
this.promise = arg;
// 本promise没有执行完的回调全部加入到新的回调列表
arg.doneList = arg.doneList.concat(this.doneList);
// 改变回调及状态
this.doneList.length = 0;
this.state = 'done';
// 跳出循环
break;
}
/*************************/
// 这里是运行then里面回调函数的地方
// 以数组形式传给下一个函数,然后保存新的值
// 判断传递的参数是否为undefined,是的话,就不用传了
if( typeof arg === 'undefined' ){
arg = this.doneList.shift().apply(this);
}else{
arg = this.doneList.shift().apply(this, [arg]);
}
}
// 保存最后的arg,保证后续的回调能继续得到参数
this.arg = arg;
}
then: function(callback){
this.doneList.push(callback);
if( this.state === 'done'){
this.state = 'pending';
this.resolve(this.arg); // 注意这里也要传递参数
}
// 这里不能在返回this了,而是一个promise对象
return this.promise;
}
// 如果then没有返回promise,那么this.promise = this;
function Promise(func){
this.state = 'pending';
this.doneList = [];
func(this.resolve.bind(this));
// 默认指向本身
this.promise = this;
}
本期完整代码
function Promise(func){
this.state = 'pending';
this.doneList = [];
func(this.resolve.bind(this));
this.promise = this;
}
Promise.prototype = {
resolve: function(){
// arguments[0]是resolve的第一个参数
var arg = arguments[0];
while(true){
if( this.doneList.length === 0 ){
this.state = 'done';
break;
}
if( arg instanceof Promise ){
this.promise = arg;
arg.doneList = arg.doneList.concat(this.doneList);
this.doneList.length = 0;
this.state = 'done';
break;
}
// 这里是运行then里面回调函数的地方
// 以数组形式传给下一个函数,然后保存新的值
// 判断传递的参数是否为undefined,是的话,就不用传了
if( typeof arg === 'undefined' ){
arg = this.doneList.shift().apply(this);
}else{
arg = this.doneList.shift().apply(this, [arg]);
}
}
// 保存最后的arg,保证后续的回调能继续得到参数
this.arg = arg;
},
then: function(callback){
this.doneList.push(callback);
if( this.state === 'done'){
this.state = 'pending';
this.resolve(this.arg); // 注意这里也要传递参数
}
return this.promise;
}
}
结束。谢谢大家阅读,如有错误或建议请给我留言或者发私信。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。