等待会抛出错误的同步操作,会返回拒绝的期约:
“`async function foo() {
console.log(1);
await (() => { throw 3; })();
}
// 给返回的期约添加一个拒绝处理程序
foo().catch(console.log);
console.log(2);
// 1
// 2
// 3
“`
如前面的例子所示,单独的 Promise.reject()不会被异步函数捕获,而会抛出未捕获错误。不过,对拒绝的期约使用 await 则会释放(unwrap)错误值(将拒绝期约返回):
“`async function foo() {
console.log(1);
await Promise.reject(3);
console.log(4); // 这行代码不会执行
}
// 给返回的期约添加一个拒绝处理程序
foo().catch(console.log);
console.log(2);
// 1
// 2
// 3
“`
await 的限制
await 关键字必须在异步函数中使用,不能在顶级上下文如标签或模块中使用。不过,定义并立即调用异步函数是没问题的。下面两段代码实际是相同的:
“`async function foo() {
console.log(await Promise.resolve(3));
}
foo();
// 3
// 立即调用的异步函数表达式
(async function() {
console.log(await Promis服务器托管网e.resolve(3));
})();
// 3
“`
此外,异步函数的特质不会扩展到嵌套函数。因此,await 关键字也只能直接出现在异步函数的定义中。在同步函数内部使用 await 会抛出 SyntaxError。
下面展示了一些会出错的例子:
“`// 不允许:await 出现在了箭头函数中
function foo() {
const syncFn = () => {
return await Promise.resolve(‘foo’);
};
console.log(sy
}
// 不允许:await 出现在了同步函数声明中
function bar() {
function syncFn() {
return await Promise.resolve(‘bar’);
}
console.log(syncFn());
}
// 不允许:await 出现在了同步函数表达式中
function baz() {
const syncFn = function() {
return await Promise.resolve(‘baz’);
};
console.log(syncFn());
}
// 不允许:IIFE 使用同步函数表达式或箭头函数
function qux() {
(function () { console.log(await Promise.resolve(‘qux’)); })();
(() => console.log(await Promise.resolve(‘qux’)))();
}
“`
停止和恢复执行
使用 await 关键字之后的区别其实比看上去的还要微妙一些。比如,下面的例子中按顺序调用了 3个函数,但它们的输出结果顺序是相反的:
“`async function foo() {
console.log(await Promise.resolve(‘foo’));
}
async function bar() {
console.log(await ‘bar’);
}
async function baz() {
console.log(‘baz’);
}
foo();
bar();
baz();
// baz
// bar
// foo
“`
async/await 中真正起作用的是 await。async 关键字,无论从哪方面来看,都不过是一个标识符。
毕竟,异步函数如果不包含 await 关键字,其执行基本上跟普通函数没有什么区别:
“`async function foo() {
console.log(2);
}
console.log(1);
foo();
console.log(3);
// 1
// 2
// 3
“`
要完全理解 await 关键字,必须知道它并非只是等待一个值可用那么简单。JavaScript 运行时在碰到 await 关键字时,会记录在哪里暂停执行。等到 await 右边的值可用了,JavaScript 运行时会向消息队列中推送一个任务,这个任务会恢复异步函数的执行。
因此,即使 await 后面跟着一个立即可用的值,函数的其余部分也会被异步求值。下面的例子演示了这一点:
“`async function foo() {
console.log(2);
await null;
console.log(4);
}
console.log(1);
foo();
console.log(3);
// 1
// 2
// 3
// 4
“`
控制台中输出结果的顺序很好地解释了运行时的工作过程:
(1) 打印 1;
(2) 调用异步函数 foo();
(3)(在 foo()中)打印 2;
(4)(在 foo()中)await 关键字暂停执行,为立即可用的值 null 向消息队列中添加一个任务;
(5) foo()退出;
(6) 打印 3;
(7) 同步线程的代码执行完毕;
(8) JavaScript 运行时从消息队列中取出任务,恢复异步函数执行;
(9)(在 foo()中)恢复执行,await 取得 null 值(这里并没有使用);
(10)(在 foo()中)打印 4;
(11) foo()返回。
如果 await 后面是一个期约,则问题会稍微复杂一些。此时,为了执行异步函数,实际上会有两个
任务被添加到消息队列并被异步求值。下面的例子虽然看起来很反直觉,但它演示了真正的执行顺序:①
“`async function foo() {
console.log(2);
console.log(await Promise.resolve(8));
console.log(9);
}
async function bar() {
“`
① TC39 对 await 后面是期约的情况如何处理做过一次修改。修改后,本例中的 Promise.resolve(8)只会生成一个异步任务。因此在新版浏览器中,这个示例的输出结果为 123458967。实际开发中,对于并行的异步操作我们通常更关注结果,而不依赖执行顺序。
console.log(4);
console.log(await 6);
console.log(7);
}
console.log(1);
foo();
console.log(3);
bar();
console.log(5);
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
“`
运行时会像这样执行上面的例子:
(1) 打印 1;
(2) 调用异步函数 foo();
(3)(在 foo()中)打印 2;
(服务器托管网4)(在 foo()中)await 关键字暂停执行,向消息队列中添加一个期约在落定之后执行的任务;
(5) 期约立即落定,把给 await 提供值的任务添加到消息队列;
(6) foo()退出;
(7) 打印 3;
(8) 调用异步函数 bar();
(9)(在 bar()中)打印 4;
(10)(在 bar()中)await 关键字暂停执行,为立即可用的值 6 向消息队列中添加一个任务;
(11) bar()退出;
(12) 打印 5;
(13) 顶级线程执行完毕;
(14) JavaScript 运行时从消息队列中取出解决 await 期约的处理程序,并将解决的值 8 提供给它;
(15) JavaScript 运行时向消息队列中添加一个恢复执行 foo()函数的任务;
(16) JavaScript 运行时从消息队列中取出恢复执行 bar()的任务及值 6;
(17)(在 bar()中)恢复执行,await 取得值 6;
(18)(在 bar()中)打印 6;
(19)(在 bar()中)打印 7;
(20) bar()返回;
(21) 异步任务完成,JavaScript 从消息队列中取出恢复执行 foo()的任务及值 8;
(22)(在 foo()中)打印 8;
(23)(在 foo()中)打印 9;
(24) foo()返回。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
基于非洲秃鹫算法的无人机航迹规划 文章目录 基于非洲秃鹫算法的无人机航迹规划 1.非洲秃鹫搜索算法 2.无人机飞行环境建模 3.无人机航迹规划建模 4.实验结果 4.1地图创建 4.2 航迹规划 5.参考文献 6.Matlab代码 摘要:本文主要介绍利用非洲秃…