v形代码为什么用promise? 用来干什么的?
异步编程,想要解决执行顺序问题, 一般都用回调函数回调函数嵌套太多,
就会形成 v形代码, 称为回调地狱.
回调本质上是把函数当做参数传给另一个函数,
从直观上来讲, 他是一个嵌套结构, 而不是线性结构,
嵌套结构太多, 非常不好阅读所以实际上 promise 是用来管理回调函数的,
而管理回调函数可以用在同步,也可以用在异步
只是用在异步时, 体验会相当的好?通过 设置状态,进行降维, promise 是用来管理状态的?
降维之后
思考
昨天学习 es6生成器的时候, 在最后一段学习中,
我们用生成器来管理了一下异步执行的顺序,
或者说我们让 嵌套结构降维, 变成了线性结构.
但用生成器的时候, 实际上没有定义什么变量是用来标记状态的.
而且我们完成下一个操作的方式是, 当完成前一个就直接执行下一个.
而promise 则是有一个叫状态的中间量.
每完成一个步骤, 就会返回一个状态,
不同的状态里, 注册着不同的函数,
一旦返回某个状态就会相应执行 该状态里的函数.
也就是监听了这个状态
似乎和之前在设计模式当中学过的 观察者模式很像.
let some = new Promise((resolve,reject) => {
reject(14);
// resolve(13);
});
some.then(
(data)=> {
console.log('success');
console.log(data);/13
},
(data) => {
console.log('fail');
console.log(data);/14
}
)
可以看出
- resolve,reject 两个函数是专门用来更改状态的.
- then(fn1,fn2) 是对应的状态要执行的函数
- resolve(参数) 会传到对应的函数
let s1 = new Promise((resolve,reject) => {
resolve("suc");
reject('fail');
});
let s2 = s1.then(
(data)=> {
console.log(data);
},
(data) => {
console.log(data);
}
)
console.log(s2 == s1);/ false
console.log(s1);
console.log(s2);
s1.then() 执行之后,默认会返回一个新的 promise实例对象
let s1 = new Promise((resolve,reject) => {
resolve("suc");
// reject('fail');
});
let s2 = s1.then(
(data)=> {
console.log(data);
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve("suc2");
// reject('fail1');
},1000)
})
},
(data) => {
console.log(data);
}
)
s2.then((data) => {console.log(data);},(data) => {console.log(data);})
console.log(s2 == s1);
image.png
在then的回调函数中return 一个new Promise 会取代默认的promise 对象
仔细观察会发现, then里的回调函数,的执行顺序在 s2 == s1之后
表明 then里注册的函数是开启了异步线程?
测试, 如果在then 回调函数中返回其他值, 会怎么样?
let s1 = new Promise((resolve,reject) => {
resolve("suc");
// reject('fail');
});
let s3;
let s2 = s1.then(
(data)=> {
console.log(data);
s3 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("suc2");
// reject('fail1');
},1000)
})
return s3
},
(data) => {
console.log(data);
}
)
s2.then((data) => {console.log(data);},(data) => {console.log(data);})
console.log(s2 == s1);/false
console.log(s2 == s3);/false
打脸, 我们惊奇的发现 s2 !== s3
这表明什么呢?...
这表明 s1.then() 里的返回值根本就不会传给 s2?
实际上 s2 是会返回一个默认的promise 对象?
可怎么解释, s2能够监听 s3的状态?
let s1 = new Promise((resolve,reject) => {
resolve("suc");
// reject('fail');
});
let s3;
let s2 = s1.then(
(data)=> {
console.log(data);
s3 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("suc2");
// reject('fail1');
},1000)
s3.then((data) => {console.log(data);},(data) => {console.log(data);})
})
return s3
},
(data) => {
console.log(data);
}
)
console.log(s2);
s2.then((data) => {console.log(data);},(data) => {console.log(data);})
console.log(s2 == s1);
console.log(s2 == s3);
image.png
神奇的地方出现了.
我们发现 在增加了 s3.then() 之后, s2.then() 报错了?
从执行顺序上来看,
在主线程进行的时候, s2 确实是一个 promise 对象
但在另一个线程当中, 读取到 s3.then()的语句时, s2突然就变成了undefined
测试一下, 如果把 s2.then() 去掉会如何?
let s1 = new Promise((resolve,reject) => {
resolve("suc");
// reject('fail');
});
let s3;
let s2 = s1.then(
(data)=> {
console.log(data);
s3 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("suc2");
// reject('fail1');
},1000)
s3.then((data) => {console.log(data)},(data) => {console.log(data);})
})
return s3
},
(data) => {
console.log(data);
}
)
console.log(s2);
// s2.then((data) => {console.log(data);},(data) => {console.log(data);})
console.log(s2 == s1);
console.log(s2 == s3);
image.png
我们发现他是会报错的.
对于此,我们只能暂时假设为, then() 里不能嵌套 then() ?
测试, 我们再给 s3.then() 换个地方
废话当然会报错, s3 还没被赋值...
let s1 = new Promise((resolve,reject) => {
resolve("suc");
// reject('fail');
});
let s3;
let s2 = s1.then(
(data)=> {
console.log(data);
s3 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("suc2");
// reject('fail1');
// 这里的代码会在异步线程里读,那个时候,已经被赋值
// 当然不会报错..
s3.then((data) => {console.log(data)},(data) => {console.log(data);})
},1000)
})
return s3
},
(data) => {
console.log(data);
}
)
console.log(s2);
// s2.then((data) => {console.log(data);},(data) => {console.log(data);})
console.log(s2 == s1);
console.log(s2 == s3);
image.png
惊奇的发现没有报错!(当然不会报错,惊奇啥..)
测试, 再把s2放回来
let s1 = new Promise((resolve,reject) => {
resolve("suc");
// reject('fail');
});
let s3;
let s2 = s1.then(
(data)=> {
console.log(data);
s3 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("suc2");
// reject('fail1');
s3.then((data) => {console.log(data)},(data) => {console.log(data);})
console.log(s3 == s2);/false
},1000)
})
return s3
},
(data) => {
console.log(data);
}
)
console.log(s2);
s2.then((data) => {console.log(data);},(data) => {console.log(data);})
console.log(s2 == s1);
console.log(s2 == s3);
image.png
发现这次不仅没有报错, 而且两个监听函数都被执行了
两个promise 监听了 同一个状态.
该怎么解释呢?
推测是这样的, 首先 s2 !== s3 表明是不同的promise 实例
但每个promise 实例会共享 resolved rejected 状态
推测 状态没在实例上定义 而在Promise原型上定义了.
所以能够进行状态共享.
测试, 如果以上推测属实, 是否会出现 s1能够监听后来的 s2?s3?
let s1 = new Promise((resolve,reject) => {
resolve("suc");
// reject('fail');
});
let s3;
let s2 = s1.then(
(data)=> {
console.log(data);
s3 = new Promise((resolve,reject) => {
setTimeout(() => {
// resolve("suc2");
reject('fail2');
s3.then((data) => {console.log(data)},(data) => {console.log(data);})
s1.then((data) => {console.log(data)},(data) => {console.log(data);})
},1000)
})
return s3
},
(data) => {
console.log(data);
}
)
console.log(s2);
s2.then((data) => {console.log(data);},(data) => {console.log(data);})
console.log(s2 == s1);
console.log(s2 == s3);
image.png
表明刚才的结论是错的
也就是, 不同实例之间, 他们的状态是不共享的
那么为什么 s2 和 s3 的状态会共享?
可能的原因是, s2 接收 return 的 s3 时, 虽然两个实例不一样,
但他们之间会共享 状态?
我已经彻底把自己弄懵逼了.
这时你就会发现, 很多时候如果直接弄懂源码就会明白为什么会有各种各样的行为.
如果不知道源码, 就会用各种测试不停的得到各种边边角角的迹象,然后要不停去猜, 实际上, 这个过程相比学习源码而言,效率是低很多的.
因为即使通过这种方式一定程度掌握了工具, 使用时的成本可能也会更高.
回到正题
链式调用 then()
let s1 = new Promise((resolve,reject) => {
console.log('start');
resolve("suc");
// reject('fail');
}).then(
(data)=> {
console.log(data);
return new Promise((resolve,reject) => {
setTimeout(() => {
// resolve("suc2");
reject('fail2');
},1000)
})
},
(data) => {
console.log(data);
}).then(() => {},(data) => {console.log(data);})
image.png
用promise 封装$.ajax
function myAjax (url,data=null,type="GET") {
return new Promise(function (resolve, reject) {
$.ajax({
type,
url,
data,
async:true,
success (data) {
resolve(data);
},
error (err) {
reject(err);
}
});
})
}
let p = myAjax('www.baidu.com');
p.then((data) => {console.log(data);},(err) => {console.log(err);});
p.then((data) => {console.log(data);},(err) => {console.log(err);});
我感觉到了这个有很大的好处,
但我还无法说清楚哪里好
所以我们试着去想一想, 都有哪些好处?
let p = new Promise((res,rej) => {
res('data');
})
p.then((data) => {console.log(data);},(err) => {console.log(err);});/ data
p.then((data) => {console.log(data);},(err) => {console.log(err);});/ data
- 之前接触回调的用法, 一个很强烈的感受是, 数据找功能函数.
- 而用promise 之后,感觉有回到了 函数调用数据的感觉. 这种感觉本身似乎更自然?
- 本来需要定义两个回调函数的, 现在可以清晰的分开来?
let p = new Promise((res,rej) => {
res('data');
})
p.then((data) => {console.log(data);
return new Promise((res,rej) => {
setTimeout(function () {
res('分支1')
},1000)
});
},(err) => {console.log(err);})
.then((data) => {console.log(data);});
p.then((data) => {console.log(data);
return new Promise((res,rej) => {
setTimeout(function () {
res('分支2')
},2000)
});
},(err) => {console.log(err);})
.then((data) => {console.log(data);});
- 可以用 在then( ) 的回调函数中 添加 return new Promise 的方式
线性添加异步任务?
疑问, then()回调里面是没有 res,rej 函数的?
那就是说, 我想要then()监听一个异步, 就必须要开启一个return new Promise?
这感觉不是很方便啊.
网友评论