Node-JS专精11_02Promise使用场景

Promise使用场景

多次处理一个结果

  • 摇骰子.then(v => v1).then(v1 => v2)
    • 1 2 3 返回小 / 4 5 6 返回大
  • 在BOSS直聘上投递阿里简历流程:
    • 必须先有网
    • 有网才能使用 BOSS直聘app或 pc
    • 登录
    • 从众多公司里搜索 阿里的 岗位
    • 投递简历

串行

一道网传面试题

1
2
3
4
5
页面有两个按A和B,以及一个输入框,
A按钮点击后发送一个请求,返回一个字符串A
B按钮点击后也发送一个请求,返回一个字符串B
返回后会把返回的字符串赋值给输入框,但是 A 和 B发送的请求时间点不同,
点击按钮的顺序也不一定,B要比A先返回,而最终效果要求是 输入框字符的顺序是 AB

这道题实际就是日常你做的如下需求

1
2
3
4
5
6
7
8
9
你打开了  百度搜索,先输入 vue,(此时已经发送了 请求a ) ,然后输入 react (此时已经发送了 请求b)

好巧不巧的是 请求a 10秒返回结果 请求b 1秒返回结果
此时 你如果按照正常的展示逻辑

你肯定先展示 react的结果 , 然后在展示 vue的结果
此时用户觉得你神经病 , 我明明搜的 react 你给我展示 vue的结果

此时你就要保证就算 react的结果先回来,我也要等到 vue的结果展示了之后在展示

正确处理的姿势:只要有一个结果返回了 就把之前的请求取消掉 ajax.cancel

生活中的高铁进站例子

1
2
3
a 和 b 两个人,分别去高铁app上买了去 北京的票 如C2212
b 比 a先买到票,但是检票的时候,a站在 b前面。
所以 无论如何,b都要在 a之后进入车厢

代码实例

  • 点击 a 按钮后立刻点击 b按钮
  • 3秒后 输入框显示 “bbb”
  • 5秒后显示 “aaa”

我们想要的结果是,不管那个结果回来,都最后显示”bbb”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button id="a">a</button>
<button id="b">b</button>
<input id="input" type="text">
<script>
let ajax1 = function(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("aaa")
},5000)
})
}

let ajax2 = function(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("bbbb")
},3000)
})
}

a.onclick = ()=>{
ajax1().then((s)=>{
input.value = s
})
}

b.onclick = ()=>{
ajax2().then((s)=>{
input.value = s
})
}
</script>
</body>
</html>

生活中的点餐取餐例子

1
2
3
4
5
6
7
8
9
10
11
餐厅有两个窗口 点餐 / 取餐
a 和 b 两个人 先后进入餐厅的点餐队列进行点餐 a 在 b 之前点餐了
a 点餐制作耗时 15分钟
b 点餐制作耗时 10分钟

a 和 b 点餐完成后, 又依次站在 取餐队列里 a在 b之前
10分钟后 b的餐好了,
但是 a 在 b之前, b 无法取餐
15分钟 a 的餐好了
a 取餐成功
于是轮到 b , b取餐成功

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button id="a">a</button>
<button id="b">b</button>
<input id="input" type="text">
<script>
let ajax1 = function(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("aaa")
},5000)
})
}

let ajax2 = function(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("bbbb")
},3000)
})
}

var 取餐队伍 = [];
var 吧台 = [];
var 问 = ()=>{
var lastN = 吧台[吧台.length -1][0];
var lastS = 吧台[吧台.length -1][1];
if(取餐队伍[0][0] === lastN){
取餐队伍[0][1](lastS);
取餐队伍.shift();
吧台.pop();
问();
}
}

a.onclick = ()=>{
let n = Math.random();
ajax1().then((s)=>{
吧台.push([n,s])
问();
})
取餐队伍.push([n,(s)=>{
input.value = s;
}])
}

b.onclick = ()=>{
let n = Math.random();
ajax2().then((s)=>{
吧台.push([n,s])
问();
})
取餐队伍.push([n,(s)=>{
input.value = s;
}])
}

</script>
</body>
</html>

并行

  • Promise.all([task1,task2]) 不好用(可以自己写一个,参考上一篇文章)
  • Promise.allSettled 又太新

Promise的错误处理

其实挺好用的

  • promise.then(s1,f1) 即可
  • 如果我想全局处理(以 axios 为例 参考它的拦截器)
    • axios 作弊表 拦截器章节
      1
      2
      3
      4
      5
      6
      7
      axios.interceptors.response.use(function (response) {
      // Do something with response data
      return response;
      }, function (error) {
      // Do something with response error
      return Promise.reject(error);
      });

语法糖

  • promise.then(s1).catch(f1)

错误处理之后

  • 如果你没有继续抛错,那么错误不再出现
  • 如果你继续抛出错误, 那么后续回调就继续处理错误
1
2
3
4
// 
Promise.resolve(`{'name':'frank'}`)
.then( s => JSON.parse(s)) // parse 失败 json 的 key必须是双引号
.then( null, (reason) => console.log("err:" + reason)) // 继续 promise 里处理

但是有人对 Promise 不满意