上一篇文章学习了 Promise
的基本使用方法后,这一章进行拓展练习。
使用 reject 而不是 throw
Promise
的构造函数和被 then
方法调用的函数基本上是在 try...catch
代码块中执行的,所以在这些代码中及时使用 throw
,程序本省也不会因为异常而终止。
如果在 Promise
中使用 throw
,会被 try...catch
捕获到,最终 promise
对象也会变为 rejected
状态。
var promise = new Promise((resolve, reject) => {
throw new Error("message");
}).catch(error => {
console.error(error);
})
上述代码运行也是可以的,但如果想把 promise
对象的状态设置为 rejected
,使用 reject
方法更加合适。
var promise = new Promise((resolve, reject) => {
reject(new Error("message"))
}).catch(error => {
console.error(error);
})
这样写,就无需调用 throw
方法抛出错误,而是使用 reject
函数传递 Error
。而且使用 throw
抛出错误,无法判断是我们主动跑出来的还是异常引起的。
而且 then
方法的第二个参数可以处理错误捕获,能连续处理多个异步而不影响程序的正常运行。
总结
- 使用
reject
比throw
安全; - 在
then
方法中能够使用reject
方法。
使用 Promise 进行顺序处理
var request = {
comment: function getComment() {
return new Promise(resolve => {
setTimeout(() => {
resolve("comment")
}, 500);
});
},
people: function getPeople() {
return new Promise(resolve => {
setTimeout(() => {
resolve("people")
}, 200);
});
}
}
function main(tasks) {
// 异步函数的返回结果无法使用普通的 return 返回出去,因为它是异步的,只能通过 then 方法传递结果
function recordValue (results, value) {
results.push(value);
return results;
}
var pushValue = recordValue.bind(null, []); // 每次都是一个新的promise,而且 results 是在闭包里面的,无需指定 this
// 使用普通 for 循环
// var promise = Promise.resolve();
// for (var i = 0; i < tasks.length; i++) {
// var task = tasks[i];
// promise = promise.then(task).then(pushValue); // 将所有任务使用 promise chain 串联起来,因为每次调用 then 方法都会返回一个新的 promise 对象
// }
// return promise;
// 使用 reduce 方法
return tasks.reduce(function (promise, task) {
return promise.then(task).then(pushValue);
}, Promise.resolve());
}
main([request.comment, request.people]).then(res => {
console.log(res);
}).catch(err => {
console.error(err);
})
多个 Promise 对象并发处理
在 js 中,可能会存在同时发起 N 个请求的场景,如若超出最大限制数,则等待;如若其中一个完成,添加请求。等到所有请求结束后,执行回调。
function wait (arr, max, callback) {
var i = 0,
fetchArr = []; // 任务队列
function toFetch () {
if (i === arr.length) {
return Promise.resolve();
}
var task = arr[i++]();
fetchArr.push(task);
// 执行完后,从任务队列中删除
task.then(() => {fetchArr.splice(fetchArr.indexOf(task), 1)});
// 如果任务队列到达上限
var p = Promise.resolve();
if (fetchArr.length >= max) {
p = Promise.race(fetchArr);
}
return p.then(() => toFetch());
}
toFetch().then(() => Promise.all(fetchArr)).then(() => {
callback();
});
}
var request = [
() => new Promise(resolve => {
setTimeout(() => {
console.log(1);
resolve(1)
}, 500)
}),
() => new Promise(resolve => {
setTimeout(() => {
console.log(2);
resolve(2)
}, 1000)
}),
() => new Promise(resolve => {
setTimeout(() => {
console.log(3);
resolve(3)
}, 200)
}),
() => new Promise(resolve => {
setTimeout(() => {
console.log(4);
resolve(4)
}, 700)
}),
() => new Promise(resolve => {
setTimeout(() => {
console.log(5);
resolve(5)
}, 1000)
})
];
wait(request, 2, function () {
console.log("end");
});
// 1
// 3
// 4
// 2
// 5
// end