前言
昨天面试去xiaoman, 提到了promise;
面对不断深入发问, 我脑子一片空白, 然后就想到了白云山;
我想怎么思考其他问题的时候没有这么思维活跃;
Promise 状态的不可逆性
Promise状态的一旦变成resolved或rejected时,Promise的状态和值就固定下来了,不论你后续再怎么调用resolve或reject方法,都不能改变它的状态和值。
var p1 = new Promise(function(resolve, reject){
resolve("success1");
resolve("success2");
});
var p2 = new Promise(function(resolve, reject){
resolve("success");
reject("reject");
});
p1.then(function(value){
console.log(value);
});
p2.then(function(value){
console.log(value);
});
// "success1"
// "success"
resolve或reject后面的代码会不会执行
当然会
then的第二个参数和catch
catch相当于then(null,function(err){ /*处理错误*/})的写法
// 写法一
new Promise((resolve)=>{
foo.bar()
}).then(res=>{
console.log(res)
},err=>{
console.log(err)
})
// ReferenceError: foo is not defined
// 写法二
new Promise((resolve)=>{
foo.bar()
}).then(res=>{
console.log(res)
kk()
}).catch(err=>{
console.log(err)
})
// ReferenceError: foo is not defined
上面代码中,catch要好于then(null,err=>{})写法, catch可以捕获前面then方法执行中的错误,也更接近同步的写法(try/catch)。因此,建议总是使用catch方法,而不使用then方法的第二个参数。如下:
new Promise((resolve)=>{
resolve(1)
}).then(res=>{
console.log(res)
kk()
}).catch(err=>{
console.log(err)
})
// ReferenceError: kk is not defined
then/catch的链式调用
首先, 在new Promise中需要执行resolve或者reject改变状态,否则不会执行then方法, 像下面then就不会执行:
var p = new Promise(function(resolve, reject){
return 1
});
p.then(function(value){
console.log(value);
return value*2;
}).then(function(value){
console.log(value);
})
// Promise {<pending>}
在状态改变后, then方法返回一个新的Promise对象,因此可以通过链式调用then方法.
catch也可以链式调用, 因为catch相当于then(null,err=>{})
函数的返回值将被用作创建then返回的Promise对象, 有如下情况:
return一个同步的值(当没有返回时,默认返回undefined),then方法将返回一个resolved状态的Promise对象,Promise对象的值就是这个返回值。return一个Promise,then方法将根据这个Promise的状态和值创建一个新的Promise对象返回。throw一个同步异常,then方法将返回一个rejected状态的Promise, 值是该异常。
var p = new Promise(function(resolve, reject){
resolve(1);
});
p.then(function(value){ //第一个then
console.log(value);
return value*2;
}).then(function(value){ //第二个then
console.log(value);
}).then(function(value){ //第三个then
console.log(value);
return Promise.resolve('resolve');
}).then(function(value){ //第四个then
console.log(value);
return Promise.reject('reject');
}).then(function(value){ //第五个then
console.log('resolve: '+ value);
}, function(err){
console.log('reject: ' + err);
})
1
2
undefined
"resolve"
"reject: reject"
再写一个return返回promise的例子:
var a = new Promise(resolve=>{
setTimeout(()=>{
resolve('5s later')
},5000)
})
var p = new Promise(function(resolve, reject){
resolve(1);
});
p.then(function(value){ //第一个then
console.log(1)
return a
}).then(function(value){ //第二个then
console.log(value);
})
// 1
// Promise {<pending>}
// 5s later
Promise.resolve()
Promise.resolve()(注意,是Promise.resolve(),而不是new Promise中的resolve)可以接收一个值或者是一个Promise对象作为参数。
当参数是普通值时,它返回一个resolved状态的Promise对象;
当参数是Promise对象时,对象的值就是这个参数;
下面的例子可以看到p1,p2是相等的
let p1 = Promise.resolve(1)
let p2 = Promise.resolve(p1)
p1 === p2
// true
then拿到数据发现不合适, 怎么触发catch
throw new Error()抛出错误. 或者 Promise.reject()
resolve和reject
当resolve的参数是一个Promise对象时,resolve会"拆箱"获取这个Promise对象的状态和值,但这个过程是异步的。
即最后的状态是根据传入的promise对象的状态确定的;
如下: 执行的是resolve(a), 但是a5秒后返回的状态是rejected,所以会执行rejected回调
var a = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('error')
},5000)
})
var p = new Promise(function(resolve, reject){
var b = resolve(a)
console.log(a === b)
});
p.then(function(value){
console.log('success')
},function(err){
console.log(err)
return err
})
// false
// Promise {<pending>}
// error
但是, reject方法不同, reject方法不存在拆箱等待, 而是直接将传入的promise对象传入下个阶段, 如下
var a = new Promise((resolve,reject)=>{
setTimeout(() => {
reject('error after 5s')
},5000)
})
var p = new Promise(function(resolve, reject){
reject(a)
})
p.then(function(value){
console.log('success')
}).catch(err1=>{ // 第一个 catch
console.log('fail: ' + err1)
return err1
}).catch(err2=>{ // 第二个 catch
console.log(err2)
return 1
}).then(res=>{
console.log(res)
})
// fail: [object Promise]
// Promise {<pending>}
// error after 5s
// 1
可以看到, p中reject了a, 直接把a传到了第一个 catch, 第一个catch中, 打印出来参数, 就是promise对象a .
在 第一个catch中return err1, 等待5秒后a变成rejected状态, 触发第二个 catch , 捕获到结果error after 5s,
最后catch 可以继续链式调用, 返回1, 相当于resolve(1), 最后then打印出1.
promise中出现异常, promise外的后面的代码会执行吗
会, Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。
new Promise(function(resolve, reject){
resolve(x+1);
});
console.log(333)
// 333
// Uncaught (in promise) ReferenceError: x is not defined
promise.all
let a = new Promise(resolve=>{setTimeout(()=>{resolve(111)},3000)})
let b = new Promise(resolve=>{setTimeout(()=>{resolve(222)},1000)})
let c = new Promise(resolve=>{setTimeout(()=>{resolve(333)},100)})
Promise.all([b,a,c]).then(res=>{
console.log(res)
})
// 结果数组也是顺序的
// [222, 111, 333]
let a = new Promise(resolve=>{setTimeout(()=>{console.log('haha');resolve(111);},3000)})
let b = new Promise((resolve,reject)=>{setTimeout(()=>{reject(222)},1000)})
let c = new Promise(resolve=>{setTimeout(()=>{resolve(333)},100)})
Promise.all([b,a,c]).then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
只要有一个错误,就会catch该错误
// 222
// haha
Promise如何按顺序执行
有一个数组,数组元素是返回Promise对象的函数,怎样顺序执行数组中的函数,即在前一个数组中的Promise resolve之后才执行下一个函数?
…
- 先生成数据, 下面代码执行完,生成10个函数组成的数组, 均返回promise对象
function createPromises(id) {
return function () {
return new Promise(resolve => {
setTimeout(() => {
console.log(id)
resolve(id)
}, 1000)
})
}
}
let list = []
for(let i = 0; i < 10; i++) {
list.push(createPromises(i))
}
// (10) [ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ]
- 递归法
// 递归调用
function promise_queue(list, i) {
if (i >= 0 && i < list.length) {
list[i]().then(() => {
promise_queue(list, i + 1)
})
}
}
promise_queue(list, 0)
- await
async function promise_queue(list) {
let index = 0
while (index >= 0 && index < list.length) {
await list[index]()
index++
}
}
promise_queue(list)
- Promise.resolve()
初始状态是Promise.resolve(),then执行第一个, 并把下一个作为then的success函数(因为then返回一个promise的话,promise状态改变后, 才会执行下一个then)
function promise_queue(list) {
var sequence = Promise.resolve()
list.forEach((item) => {
sequence = sequence.then(item)
})
return sequence
}
- reduce
list.reduce((pre,next)=>pre.then(next),Promise.resolve());
promise实现每隔一段时间执行一次函数, 执行n次 , 不用await
每隔interval毫秒, 执行一次fn函数, 执行time次:
function interval(fn, interval, time){
let f = () => new Promise(resolve=>{
setTimeout(()=>{
fn()
resolve()
},interval)
})
let a = Promise.resolve()
for(let i = 0; i< time; i++){
a = a.then(f)
}
}
本文深入探讨Promise的工作原理,包括状态的不可逆性、resolve/reject的执行机制、then/catch的链式调用、错误处理策略及Promise.all的用法。通过实例解析,帮助读者掌握Promise的高级应用。
408

被折叠的 条评论
为什么被折叠?



