在javascript中,await关键字只能在async函数内部使用,它用于暂停async函数的执行,直到其后的promise被解决(resolved)或拒绝(rejected)。mdn文档指出,await表达式会将其操作数以与promise.resolve()相同的方式进行处理:它总是被转换为一个原生promise,然后被等待。这意味着:
为了更好地理解await在不同场景下的行为,我们通过以下几个示例进行深入分析。
当await一个本身是async的函数,并且该函数内部抛出异常时,其行为符合异步预期。
async function load(closure) { try { await closure(); // closure 是一个 async 函数 } catch (error) { console.log("error"); } finally { console.log("finished"); } } // 示例 1: closure 是一个 async 函数 load(async () => { throw new Error("Async error"); }); console.log("hello");
输出:
hello error finished
解释: 在这个例子中,closure本身是一个async函数。当async函数内部抛出错误时,它会返回一个被拒绝的Promise。await closure()会等待这个被拒绝的Promise,从而暂停load函数的执行。因此,console.log("hello")会先执行,然后load函数捕获到错误并执行error和finished。这是await的典型异步行为。
这是最核心的场景,也是导致“同步”行为的原因。当await一个非async函数,且该函数在执行时立即抛出异常,await机制将无法介入其Promise转换过程。
立即学习“Java免费学习笔记(深入)”;
async function load(closure) { try { await closure(); // closure 是一个普通函数,同步抛出错误 } catch (error) { console.log("error"); } finally { console.log("finished"); } } // 示例 2: closure 是一个普通函数,同步抛出错误 load(() => { throw new Error("Sync error"); }); console.log("hello");
输出:
error finished hello
解释: 在这个例子中,closure是一个普通的同步函数。当await closure()被调用时,closure()会立即执行。由于它同步地抛出了一个Error,这个错误在任何Promise被创建或Promise.resolve()有机会包装返回值之前就已经发生了。
try...catch块会立即捕获这个同步抛出的错误,导致console.log("error")和console.log("finished")立即执行。由于await并没有接收到一个Promise(或者一个可以被Promise.resolve()转换为Promise的值),load函数并没有被暂停。因此,console.log("hello")会在load函数内部的catch和finally块执行完毕后才执行,从而看起来像是一个同步执行流程。await在这里实际上没有起到暂停异步函数的作用,因为它从未接收到可等待的Promise。
当await一个非async函数,但该函数返回一个普通值时,await会将其转换为Promise并进行异步处理。
async function load(closure) { try { await closure(); // closure 是一个普通函数,返回一个值 } catch (error) { console.log("error"); } finally { console.log("finished"); } } // 示例 3: closure 是一个普通函数,返回一个值 load(() => { return 1; }); console.log("hello");
输出:
hello finished
解释: 在此例中,closure()返回了数值1。根据await的机制,await 1等同于await Promise.resolve(1)。Promise.resolve(1)会返回一个已解决的Promise,await会等待这个Promise。因此,load函数会被暂停,console.log("hello")会先执行。当Promise.resolve(1)解决后,load函数恢复执行,finally块中的console.log("finished")被打印。
如果非async函数显式地返回一个被拒绝的Promise,行为与async函数抛出异常类似。
async function load(closure) { try { await closure(); // closure 是一个普通函数,返回一个被拒绝的Promise } catch (error) { console.log("error"); } finally { console.log("finished"); } } // 示例 4: closure 是一个普通函数,返回一个被拒绝的Promise load(() => { return Promise.reject("Rejected promise"); }); console.log("hello");
输出:
hello error finished
解释:closure()直接返回了一个被拒绝的Promise。await Promise.reject("Rejected promise")会等待这个被拒绝的Promise,并导致load函数被暂停。因此,console.log("hello")会先执行。随后,load函数捕获到被拒绝的Promise,执行error和finished。这再次证明了await在处理Promise时的异步特性。
理解这些细微之处对于编写健壮且可预测的JavaScript异步代码至关重要。await的强大之处在于它让异步代码看起来像同步代码,但其底层机制仍然是基于事件循环和Promise的。当同步错误意外地“跳过”了Promise创建流程时,就会出现这种看似同步的特殊行为。
以上就是深入理解 JavaScript await 行为:非异步函数抛出异常的同步效应的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号