比如说做一件事分几个动作: step1 、 step2 、 finish ,前两个是异步的, step1 完成后才能执行 step2 (然后 finish )。我想到用 Promise 这么写:
let prom = new Promise((resolve, reject) => {
// step1 ,用 setTimeout 模拟一下异步
setTimeout(() => resolve('1'), 1000);
// 先忽略 reject 相关动作
});
prom.then(data => {
// step2
setTimeout(() => {
prom.then(data => {
// finish
console.log(`完成: ${data}`)
});
}, 1000);
});
可这样不就成 callback hell 了吗?而且从 step2 往后传数据也不方便。
由此引发的还有 step1 出错执行reject()
如何中止整个过程的问题。
还是我对 Promise 的理解有问题?
1
leojoy710 2016-05-18 17:20:10 +08:00 1
then 可以 return 一个 promise...然后就可以继续 then 了...
|
2
SilentDepth OP @leojoy710 是可以链式调用,但不能让 step2 的异步完成后再执行 finish
|
3
spritevan 2016-05-18 17:30:25 +08:00
|
4
leojoy710 2016-05-18 17:32:01 +08:00
@SilentDepth step1.then((d) => step2(d)).then(() => finish())
|
5
napsterwu 2016-05-18 17:37:46 +08:00
链式调用的时候,你可以用.catch ,任何一步出错都会跳到最后的 reject ,就和 try catch 一样。然后只要你写的每一个 Promise 都有 return Promise ,就可以链式调用。只是我不知道怎么让第一个 Promise 的数据传递到最后,我就用了 block variable 。
|
6
napsterwu 2016-05-18 17:46:34 +08:00
|
7
markmx 2016-05-18 17:50:28 +08:00
建议还是使用匿名方法吧..写的太长了...还是不够整齐的.
Promise 你当做一个流程的管理.不要把逻辑代码过多的放进去 |
8
bdbai 2016-05-18 18:22:13 +08:00 via Android
试试 async/await
|
9
SilentDepth OP @leojoy710
按这个思路试了一下,结果不符预期: <script src="https://gist.github.com/SilentDepth/bd558eb503b11f733f97be3322d83b51.js"></script> step2 也是一个异步动作, finish 需要 step2 完成后才能执行 |
10
xqin 2016-05-18 18:50:11 +08:00
```
new Promise((resolve, reject) => { //step 1 setTimeout(() => resolve('1'), 1000); }).then(data => { return new Promise((resolve, reject) => { //step 2 setTimeout(() => resolve([data, '2']), 1000); }).then(data => { //finish console.log('finish', data); }); }); ``` |
11
magicdawn 2016-05-18 19:02:40 +08:00
|
12
vghdjgh 2016-05-18 19:20:20 +08:00
function step1Async() {
return new Promise((resolve, reject) => { step1((error, result) => { if (error) { reject(error); } else { resolve(result); } }); }); } ... try{ const result = await step1Async(); await step2Async(); await finishAsync(); } catch(error){ // error } |
13
vghdjgh 2016-05-18 19:21:17 +08:00
格式全乱了,看来这里不适合讨论代码。。。
|
14
vghdjgh 2016-05-18 19:25:09 +08:00
<script src="https://gist.github.com/plantain-00/ec1a8c6a8ea857ce53d3c066949d60b2.js"></script>
|
15
xjp 2016-05-18 19:29:18 +08:00
我一般不喜欢使用 Promise 构造函数 我一般这么用的
``` let prom = new Promise(); prom.then(data => { // step 2 let prom1 = new Promise(); setTimeout(() => prom1.resolve('2'), 1000); return prom1; }).then(data =>{ // step 3 return "3"; }).then(data =>{ // finish console.log('finish', data); }); // step 1 setTimeout(() => prom.resolve('1'), 1000); ``` 如果 then 里 return 的值是 promise 则将 resolve 的结果传入下一个 then 如果 then 里 return 返回的不是 promise 则将结果直接传入下一个 then |
16
mcfog 2016-05-18 19:43:24 +08:00 1
这里的陷阱在于你的 setTimeout 是 callback 风格的,不是 promise 风格的
一定要那 setTimeout 打比方(或者比如外部库是 callback 风格)的话,一定要先转换成 promise 风格 ``` function step1() { console.log('step1 start'); return new Promise(resolve => {setTimeout( ()=> {resolve('step1 result');}, 1000)}); } function step2(data) { console.log('step2, param is', data); return new Promise(resolve => {setTimeout( ()=> {resolve('step2 result');}, 1000)}); } //正常的 promise 串行代码如下 step1() .then(step2) .then(result => { console.log('finish, param is', result) }); ``` bluebird 等三方 promise 一般都提供标准的 promisify 方法做这件事 |
17
FlowMEMO 2016-05-18 19:57:13 +08:00
赞同 @mcfog . promise 用的爽前提是你的异步函数已经包成 promise 了,而不是每次都在 then()里生成 promise.
|
18
otakustay 2016-05-18 20:47:51 +08:00 via iPad
核心是你先把 setTimeout 改成返回 Promise 的方法,然后就爽了
|
19
colatin 2016-05-18 22:03:37 +08:00
Promise.delay
|
20
jerray 2016-05-18 23:30:23 +08:00
|
21
leojoy710 2016-05-19 08:16:50 +08:00
@SilentDepth 原来是我说的太简略...请看 @mcfog 的回复...
|
22
hging 2016-05-19 08:51:12 +08:00 via iPhone
async 大法好
|
23
SilentDepth OP 感谢 @napsterwu @xjp @mcfog
我发现我的问题在于不知道`then()`的参数返回一个 Promise 会并入外部的 Promise composition ( MDN 没有写啊……),看来还是我对 Promise 的理解不到位。 现在的问题就是中间的`catch()`如何优雅地中止掉整个 composition 。调用`reject()`后会直接跳到后面最近的 rejection handler ,然后就继续走正常路线了。不是应该有个`Promise.prototype.cancel()`之类的方法吗? to @xjp : 另外,我说的是 ES2015 里的 Promise ,构造函数的参数必须要有,这个怪我一开始没说清。 |
24
napsterwu 2016-05-19 09:43:19 +08:00
@SilentDepth Promise.all()
|
25
hantsy 2016-05-19 10:13:18 +08:00
用 RxJS 代替。
|
26
SilentDepth OP @napsterwu `Promise.all()`就不是分步了呀
|
27
napsterwu 2016-05-19 13:57:32 +08:00
@SilentDepth 我上面不是还发了个链接演示怎么分步么
|
28
napsterwu 2016-05-19 13:58:15 +08:00
|
29
napsterwu 2016-05-19 13:58:58 +08:00
@SilentDepth 抱歉没搞好,左上角要选择 ES6
|
30
SilentDepth OP @napsterwu 我是说「 step2 的异步成功后执行 finish 」这个需求用`Promise.all()`不能实现
|
31
SilentDepth OP 通过空 Promise 实现了一个中止过程功能:
https://gist.github.com/SilentDepth/67866e565946e84b1409d16d294b6181 但感觉这样不优雅。 Any idea? |
32
yolio2003 2016-05-19 19:47:16 +08:00
各种大神回复了,楼主还是没明白。。。
|
33
yolio2003 2016-05-19 22:53:59 +08:00
所以我觉得其实是 promise 本身的问题 (逃
|
34
jimliang 2016-05-20 00:08:16 +08:00
楼主对 Promise 根本不熟练,其次 step1 和 step2 的逻辑就是一样的,可以封装在一起。两行搞定
``` const step = data=>new Promise(resolve=>setTimeout(resolve, 1000, data)); step('1').then(step).then(data=> console.log(`完成: ${data}`)); ``` |
35
SilentDepth OP @jimliang 刚学。如果是需要各个动作可以独立工作呢?
|
36
jimliang 2016-05-20 09:35:30 +08:00
@SilentDepth 如果是独立的就另外处理。 Promise 的重点是形成 Promise 链, then 的函数要返回具体的对象或者 Promise 作为下一个传递。我看你把一个 Promise then 了两次,也就是说 resolve 后两个 then 都会执行并不会顺着一条链执行了。
|