Promise
前端编程是一个单线程的模型,但是其中包含许多异步的动作,异步的动作应该通过以下四步来完成:
- 发起请求;
- 事件处理函数结束;
- 请求结束;
- 进入回调函数;
上述的基于回调函数解决方案不够好,当事件请求过多时,可能会产生 Callback Hell 现象。使用 Promise 可以解决回调函数的问题。
Promise 的创建和使用
我们首先来看一个回调函数的例子,在这个例子中,我们在回调函数中进行简单的 number 加法:
typescript
function add(a: number, b: number, callback: (res: number) => void): void {
setTimeout(() => {
callback(a + b)
}, 2000)
}
add(2, 3, res => {
console.log('2 + 3', res)
add(res, 4, res2 => {
console.log('2 + 3 + 4', res2)
})
})
程序将先后输出:
typescript
[LOG]: "2 + 3", 5
[LOG]: "2 + 3 + 4", 9
现在我们将回调函数改为 Promise:
typescript
function add(a: number, b: number): Promise<number> {
return new Promise(
(resolve, reject) => {
setTimeout(() => {
resolve(a + b)
}, 2000)
}
)
}
add(2, 3).then(res => {
console.log('2 + 3', res)
})
可以使用 then 方法来完成多个计算结果的顺序打印:
typescript
function add(a: number, b: number): Promise<number>{
return new Promise(
(resolve, reject) => {
if(b % 17 == 0) {
reject(`bad number ${b}`)
}
setTimeout(
() => {
resolve(a + b)
}, 2000
)
}
)
}
function mul(a: number, b: number): Promise<number>{
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a * b)
}, 3000)
// resolve(a * b)
})
}
// (2 + 3) * 4 + 5
add(2, 3).then(res => {
console.log("2 + 3", res)
return mul(res, 5)
}).then(res => {
console.log("(2 + 3) * 4", res)
return add(res, 5)
}).then(res => {
console.log("(2 + 3) * 4 + 5", res)
return add(res, 17)
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
输出的结果是:
typescript
[LOG]: "2 + 3", 5
[LOG]: "(2 + 3) * 4", 25
[LOG]: "(2 + 3) * 4 + 5", 30
[LOG]: "bad number 17"
需要注意的是,在使用 then 方法时,一定要在 then 作为参数的箭头函数当中将下一步要做的行为返回出去,这样才能创建多个 Promise。
同时等待多个 Promise
现在我们希望通过 Promise 来计算(2 + 3) * (4 + 5)
的结果,使用 Promise.all 方法来完成:
typescript
// (2+3)*(4+5)
Promise.all([add(2, 3), add(4, 5)]).then(res => {
let [a, b] = res
return mul(a, b)
}).then(res => {
console.log("(2+3)*(4+5)", res)
})
可以使用 Promise.race 来看哪个 Promise 首先执行完毕:
typescript
Promise.race([add(2, 3), add(4, 5)]).then(res => {
console.log(res)
})
Promise 最大的用处是将多种行为串联起来,可以解决 Callback Hell 的问题。