异步编程模式
JavaScript 异步编程模式
Promise 编排
异常处理
最容易犯的错误,没有使用 catch
去捕获 then
里抛出的报错:
// snippet1
somePromise()
.then(function() {
throw new Error("oh noes");
})
.catch(function(err) {
// I caught your error! :)
});
// snippet2
somePromise().then(
function resolve() {
throw new Error("oh noes");
},
function reject(err) {
// I didn't catch your error! :(
}
);
这里的问题在于
下面的两个示例返回结果是不一样的:
// example1
Promise.resolve("foo")
.then(Promise.resolve("bar"))
.then(function(result) {
console.log(result); // foo
});
// example2
Promise.resolve("foo")
.then(function() {
return Promise.resolve("bar");
})
.then(function(result) {
console.log(result); // bar
});
引入此文中对于
async function waitAndMaybeReject() {
// Wait one second
await new Promise(r => setTimeout(r, 1000));
// Toss a coin
const isHeads = Boolean(Math.round(Math.random()));
if (isHeads) return "yay";
throw Error("Boo!");
}
async function foo() {
try {
// Wait for the result of waitAndMaybeReject() to settle,
// and assign the fulfilled value to fulfilledValue:
const fulfilledValue = await waitAndMaybeReject();
// If the result of waitAndMaybeReject() rejects, our code
// throws, and we jump to the catch block.
// Otherwise, this block continues to run:
return fulfilledValue;
} catch (e) {
return "caught";
}
}
避免异步混淆与性能损耗
(async () => {
const pizzaData = await getPizzaData(); // async call
const drinkData = await getDrinkData(); // async call
const chosenPizza = choosePizza(); // sync call
const chosenDrink = chooseDrink(); // sync call
await addPizzaToCart(chosenPizza); // async call
await addDrinkToCart(chosenDrink); // async call
orderItems(); // async call
})();
所有这些语句一个接一个地执行。这里没有并行逻辑。细想一下:为什么我们要在获取饮料列表之前等待获取披萨列表?我们应该尝试一起获取这两个列表。然而,当我们需要选择一个披萨的时候,我们确实需要在这之前获取披萨列表。对于饮料来说,道理类似。因此,我们可以总结如下:披萨相关的任务和饮料相关的任务可以并行发生,但是披萨
async function orderItems() {
const items = await getCartItems(); // async call
const noOfItems = items.length;
for (const i = 0; i < noOfItems; i++) {
await sendRequest(items[i]); // async call
}
}
找出那些依赖其它语句执行的语句,将相互依赖的语句包在一个
async function selectPizza() {
const pizzaData = await getPizzaData(); // async call
const chosenPizza = choosePizza(); // sync call
await addPizzaToCart(chosenPizza); // async call
}
async function selectDrink() {
const drinkData = await getDrinkData(); // async call
const chosenDrink = chooseDrink(); // sync call
await addDrinkToCart(chosenDrink); // async call
}
(async () => {
const pizzaPromise = selectPizza();
const drinkPromise = selectDrink();
await pizzaPromise;
await drinkPromise;
orderItems(); // async call
})()(
// Although I prefer it this way
async () => {
Promise.all([selectPizza(), selectDrink()]).then(orderItems); // async call
}
)();
在第二个例子中,我们需要处理不确定数量的
async function orderItems() {
const items = await getCartItems(); // async call
const noOfItems = items.length;
const promises = [];
for (const i = 0; i < noOfItems; i++) {
const orderPromise = sendRequest(items[i]); // async call
promises.push(orderPromise); // sync call
}
await Promise.all(promises); // async call
}