当前位置: 首页 > news >正文

邢台做网站优化价格网站基本维护

邢台做网站优化价格,网站基本维护,北京网站优化排名,万能引流下载软件异步函数 ES8 的 async/await 旨在解决利用异步结构组织代码的问题。为此#xff0c;ECMAScript 对函数进行了扩展#xff0c;为其增加了两个新关键字#xff1a;async 和 await。 1. async async 关键字用于声明异步函数。这个关键字可以用在函数声明、函数表达式、箭头…异步函数 ES8 的 async/await 旨在解决利用异步结构组织代码的问题。为此ECMAScript 对函数进行了扩展为其增加了两个新关键字async 和 await。 1. async async 关键字用于声明异步函数。这个关键字可以用在函数声明、函数表达式、箭头函数和方法上 async function foo() {} let bar async function() {}; let baz async () {}; class Qux { async qux() {} } 使用 async 关键字可以让函数具有异步特征但总体上其代码仍然是同步求值的。而在参数或闭包方面异步函数仍然具有普通 JavaScript 函数的正常行为。正如下面的例子所示foo()函数仍然会在后面的指令之前被求值 async function foo() { console.log(1); } foo(); console.log(2); // 1 // 2 不过异步函数如果使用 return 关键字返回了值如果没有 return 则会返回 undefined这个值会被 Promise.resolve()包装成一个期约对象。异步函数始终返回期约对象。在函数外部调用这个函数可以得到它返回的期约 async function foo() { console.log(1); return 3; } // 给返回的期约添加一个解决处理程序 foo().then(console.log); console.log(2); // 1 // 2 // 3 当然直接返回一个期约对象也是一样的 async function foo() { console.log(1); return Promise.resolve(3); } // 给返回的期约添加一个解决处理程序 foo().then(console.log); console.log(2); // 1 // 2 // 3 异步函数的返回值期待但实际上并不要求一个实现 thenable 接口的对象但常规的值也可以。如果返回的是实现 thenable 接口的对象则这个对象可以由提供给 then()的处理程序“解包”。如果不是则返回值就被当作已经解决的期约。下面的代码演示了这些情况 // 返回一个原始值 async function foo() { return foo; } foo().then(console.log); // foo // 返回一个没有实现 thenable 接口的对象 async function bar() { return [bar]; } bar().then(console.log); // [bar] // 返回一个实现了 thenable 接口的非期约对象 async function baz() { const thenable { then(callback) { callback(baz); } }; return thenable; } baz().then(console.log); // baz // 返回一个期约 async function qux() { return Promise.resolve(qux); } qux().then(console.log); // qux 与在期约处理程序中一样在异步函数中抛出错误会返回拒绝的期约 async function foo() { console.log(1); throw 3; } // 给返回的期约添加一个拒绝处理程序 foo().catch(console.log); console.log(2); // 1 // 2 // 3 不过拒绝期约的错误不会被异步函数捕获 async function foo() { console.log(1); Promise.reject(3); } // Attach a rejected handler to the returned promise foo().catch(console.log); console.log(2); // 1 // 2 // Uncaught (in promise): 3 2. await 因为异步函数主要针对不会马上完成的任务所以自然需要一种暂停和恢复执行的能力。使用 await关键字可以暂停异步函数代码的执行等待期约解决。来看下面之前在Promise章节中出现过的例子 let p new Promise((resolve, reject) setTimeout(resolve, 1000, 3)); p.then((x) console.log(x)); // 3 使用 async/await 可以写成这样 async function foo() { let p new Promise((resolve, reject) setTimeout(resolve, 1000, 3)); console.log(await p); } foo(); // 3 注意await 关键字会暂停执行异步函数后面的代码让出 JavaScript 运行时的执行线程。这个行为与生成器函数中的 yield 关键字是一样的。await 关键字同样是尝试“解包”对象的值然后将这个值传给表达式再异步恢复异步函数的执行。 await 关键字的用法与 JavaScript 的一元操作一样。它可以单独使用也可以在表达式中使用如下面的例子所示 // 异步打印foo async function foo() { console.log(await Promise.resolve(foo)); } foo(); // foo // 异步打印bar async function bar() { return await Promise.resolve(bar); } bar().then(console.log); // bar // 1000 毫秒后异步打印baz async function baz() { await new Promise((resolve, reject) setTimeout(resolve, 1000)); console.log(baz); } baz(); // baz1000 毫秒后 await 关键字期待但实际上并不要求一个实现 thenable 接口的对象但常规的值也可以。如果是实现 thenable 接口的对象则这个对象可以由 await 来“解包”。如果不是则这个值就被当作已经解决的期约。下面的代码演示了这些情况 // 等待一个原始值 async function foo() { console.log(await foo); } foo(); // foo // 等待一个没有实现 thenable 接口的对象 async function bar() { console.log(await [bar]); } bar(); // [bar] // 等待一个实现了 thenable 接口的非期约对象 async function baz() { const thenable { then(callback) { callback(baz); } }; console.log(await thenable); } baz(); // baz // 等待一个期约 async function qux() { console.log(await Promise.resolve(qux)); } qux(); // qux 等待会抛出错误的同步操作会返回拒绝的期约 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 3. await 的限制 await 关键字必须在异步函数中使用不能在顶级上下文如script标签或模块中使用。不过定义并立即调用异步函数是没问题的。下面两段代码实际是相同的 async function foo() { console.log(await Promise.resolve(3)); } foo(); // 3 // 立即调用的异步函数表达式 (async function() { console.log(await Promise.resolve(3)); })(); // 3 此外异步函数的特质不会扩展到嵌套函数。因此await 关键字也只能直接出现在异步函数的定义中。在同步函数内部使用 await 会抛出SyntaxError。 下面展示了一些会出错的例子 // 不允许await 出现在了箭头函数中 function foo() { const syncFn () { return await Promise.resolve(foo); }; console.log(syncFn());} // 不允许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 后面是一个期约则问题会稍微复杂一些。此时为了执行异步函数实际上会有两个任务被添加到消息队列并被异步求值。下面的例子虽然看起来很反直觉但它演示了真正的执行顺序(TC39 对 await 后面是期约的情况如何处理做过一次修改。修改后本例中的Promise.resolve(8)只会生成一个异步任务。因此在新版浏览器中这个示例的输出结果为 123458967。实际开发中对于并行的异步操作我们通常更关注结果而不依赖执行顺序。——译者注) async function foo() { console.log(2); console.log(await Promise.resolve(8)); console.log(9); } async function bar() {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()返回。 异步函数策略 因为简单实用所以异步函数很快成为 JavaScript 项目使用最广泛的特性之一。不过在使用异步函数时还是有些问题要注意。 1. 实现 sleep() 很多人在刚开始学习 JavaScript 时想找到一个类似 Java 中Thread.sleep()之类的函数好在程序中加入非阻塞的暂停。以前这个需求基本上都通过 setTimeout()利用 JavaScript 运行时的行为来实现的。 有了异步函数之后就不一样了。一个简单的箭头函数就可以实现sleep() async function sleep(delay) { return new Promise((resolve) setTimeout(resolve, delay)); } async function foo() { const t0 Date.now(); await sleep(1500); // 暂停约 1500 毫秒 console.log(Date.now() - t0); } foo(); // 1502 2. 利用平行执行 如果使用 await 时不留心则很可能错过平行加速的机会。来看下面的例子其中顺序等待了 5 个随机的超时 async function randomDelay(id) { // 延迟 0~1000 毫秒 const delay Math.random() * 1000; return new Promise((resolve) setTimeout(() { console.log(${id} finished); resolve(); }, delay)); } async function foo() { const t0 Date.now(); await randomDelay(0); await randomDelay(1); await randomDelay(2); await randomDelay(3); await randomDelay(4); console.log(${Date.now() - t0}ms elapsed); } foo(); // 0 finished // 1 finished // 2 finished // 3 finished // 4 finished // 877ms elapsed 用一个 for 循环重写就是 async function randomDelay(id) { // 延迟 0~1000 毫秒 const delay Math.random() * 1000; return new Promise((resolve) setTimeout(() { console.log(${id} finished); resolve(); }, delay)); } async function foo() { const t0 Date.now(); for (let i 0; i 5; i) { await randomDelay(i); } console.log(${Date.now() - t0}ms elapsed); } foo(); // 0 finished // 1 finished // 2 finished // 3 finished // 4 finished // 877ms elapsed 就算这些期约之间没有依赖异步函数也会依次暂停等待每个超时完成。这样可以保证执行顺序但总执行时间会变长。 如果顺序不是必需保证的那么可以先一次性初始化所有期约然后再分别等待它们的结果。比如 async function randomDelay(id) { // 延迟 0~1000 毫秒 const delay Math.random() * 1000; return new Promise((resolve) setTimeout(() { setTimeout(console.log, 0, ${id} finished); resolve(); }, delay)); } async function foo() { const t0 Date.now(); const p0 randomDelay(0); const p1 randomDelay(1); const p2 randomDelay(2); const p3 randomDelay(3); const p4 randomDelay(4); await p0; await p1; await p2; await p3; await p4; setTimeout(console.log, 0, ${Date.now() - t0}ms elapsed); } foo(); // 1 finished // 4 finished // 3 finished // 0 finished // 2 finished // 877ms elapsed 用数组和 for 循环再包装一下就是 async function randomDelay(id) {// 延迟 0~1000 毫秒const delay Math.random() * 1000return new Promise((resolve) setTimeout(() {console.log(${id} finished)resolve()}, delay)) }async function foo() {const t0 Date.now()const promises Array(5).fill(null).map((_, i) randomDelay(i))for (const p of promises) {await p}console.log(${Date.now() - t0}ms elapsed) } foo()// 4 finished // 2 finished // 1 finished // 0 finished // 3 finished // 877ms elapsed注意虽然期约没有按照顺序执行但 await 按顺序收到了每个期约的值 async function randomDelay(id) { // 延迟 0~1000 毫秒 const delay Math.random() * 1000; return new Promise((resolve) setTimeout(() { console.log(${id} finished); resolve(id); }, delay)); } async function foo() { const t0 Date.now(); const promises Array(5).fill(null).map((_, i) randomDelay(i)); for (const p of promises) { console.log(awaited ${await p}); } console.log(${Date.now() - t0}ms elapsed); } foo(); // 1 finished // 2 finished // 4 finished // 3 finished // 0 finished // awaited 0 // awaited 1 // awaited 2 // awaited 3 // awaited 4 // 645ms elapsed 3. 串行执行期约 在 11.2 节我们讨论过如何串行执行期约并把值传给后续的期约。使用 async/await期约连锁会变得很简单 function addTwo(x) {return x 2;} function addThree(x) {return x 3;} function addFive(x) {return x 5;} async function addTen(x) { for (const fn of [addTwo, addThree, addFive]) { x await fn(x); } return x; } addTen(9).then(console.log); // 19 这里await 直接传递了每个函数的返回值结果通过迭代产生。当然这个例子并没有使用期约如果要使用期约则可以把所有函数都改成异步函数。这样它们就都返回期约了 async function addTwo(x) {return x 2;} async function addThree(x) {return x 3;} async function addFive(x) {return x 5;} async function addTen(x) { for (const fn of [addTwo, addThree, addFive]) { x await fn(x); } return x; } addTen(9).then(console.log); // 19 4. 栈追踪与内存管理 期约与异步函数的功能有相当程度的重叠但它们在内存中的表示则差别很大。看看下面的例子它展示了拒绝期约的栈追踪信息 function fooPromiseExecutor(resolve, reject) { setTimeout(reject, 1000, bar); } function foo() { new Promise(fooPromiseExecutor); } foo(); // Uncaught (in promise) bar // setTimeout // setTimeout (async) // fooPromiseExecutor // foo 根据对期约的不同理解程度以上栈追踪信息可能会让某些读者不解。栈追踪信息应该相当直接地表现 JavaScript 引擎当前栈内存中函数调用之间的嵌套关系。在超时处理程序执行时和拒绝期约时我 们看到的错误信息包含嵌套函数的标识符那是被调用以创建最初期约实例的函数。可是我们知道这些函数已经返回了因此栈追踪信息中不应该看到它们。 答案很简单这是因为 JavaScript 引擎会在创建期约时尽可能保留完整的调用栈。在抛出错误时调用栈可以由运行时的错误处理逻辑获取因而就会出现在栈追踪信息中。当然这意味着栈追踪信息 会占用内存从而带来一些计算和存储成本。 如果在前面的例子中使用的是异步函数那又会怎样呢比如 function fooPromiseExecutor(resolve, reject) { setTimeout(reject, 1000, bar); } async function foo() { await new Promise(fooPromiseExecutor); } foo(); // Uncaught (in promise) bar // foo // async function (async) // foo 这样一改栈追踪信息就准确地反映了当前的调用栈。fooPromiseExecutor()已经返回所以它不在错误信息中。但 foo()此时被挂起了并没有退出。JavaScript 运行时可以简单地在嵌套函数中存储指向包含函数的指针就跟对待同步函数调用栈一样。这个指针实际上存储在内存中可用于在出错时生成栈追踪信息。这样就不会像之前的例子那样带来额外的消耗因此在重视性能的应用中是可以优先考虑的。 小结 长期以来掌握单线程 JavaScript 运行时的异步行为一直都是个艰巨的任务。随着 ES6 新增了期约和 ES8 新增了异步函数ECMAScript 的异步编程特性有了长足的进步。通过期约和 async/await不仅可以实现之前难以实现或不可能实现的任务而且也能写出更清晰、简洁并且容易理解、调试的代码。 期约的主要功能是为异步代码提供了清晰的抽象。可以用期约表示异步执行的代码块也可以用期约表示异步计算的值。在需要串行异步代码时期约的价值最为突出。作为可塑性极强的一种结构期约可以被序列化、连锁使用、复合、扩展和重组。 异步函数是将期约应用于 JavaScript 函数的结果。异步函数可以暂停执行而不阻塞主线程。无论是编写基于期约的代码还是组织串行或平行执行的异步代码使用异步函数都非常得心应手。异步函数可以说是现代 JavaScript 工具箱中最重要的工具之一。
http://www.pierceye.com/news/198546/

相关文章:

  • 网站集群建设价格wordpress 加文章列表
  • 官方网站案例用ps做网站主页
  • 做名片的网站推广型网站建设销售
  • 河南省建设执业资格注册中心网站网站推广公司 sit
  • 来年做那个网站致富网站工作室 需要什么手续
  • 宜兴网站建设哪家好网站建设设计公司排名
  • 婚庆公司网站怎么做wordpress 首页置顶
  • 电商网站开发人员结构江苏住房和城乡建设厅网站首页
  • 快速建站的模板陕西省建设网三类人员继续教育
  • 谷歌浏览器对做网站有什么好处广州最好网站策划
  • 西安北郊做网站重庆手机软件开发
  • 怀化刚刚发生的大事台州seo服务
  • 织梦做的网站打开空白巴中网站制作公司
  • 如何使用jq做弹幕网站设计漂亮的网站
  • 电商网站是获取流量广西南宁网站排名优化
  • 网站板块设计有哪些开发网站监控推荐
  • 江西建设局网站广东网站建设类公司
  • 深圳网站制作设计艾佳工业设计
  • 怎么查看网站啥系统做的宁波网站设计制作
  • 温岭手机网站建设合肥企业展厅设计公司
  • 网站建设和制作怎么赚钱外贸网站建设服务器
  • 长沙自动化网站建设瑞安地区建设网站
  • 中山做网站费用网页制作简明教程
  • 芜湖做网站需要多少钱青岛网站建设公司怎么选
  • 塑胶 东莞网站建设企业网络推广培训
  • wordpress五分钟建站手机网站 cms
  • 网站前台后台河南省建设工程质量协会网站
  • wordpress无法拖动小工具长沙seo网站推广
  • 网站的推广方案的内容有哪些网站建设所需技术
  • 手机微网站怎么制作的威特视频网站建设方案