使用顶层await简化JS代码

  发布时间:2025-11-05 08:38:13   作者:玩站小弟   我要评论
JavaScript 是一种流行的编程语言,最初被设计为单线程和同步的语言,意味着程序需要在不等待获取外部资源或者耗时的计算的情况下一步一步的运行。如果脚本需要这样的资源或计算,这种同步行为将导致错误 。

 JavaScript 是使用一种流行的编程语言,最初被设计为单线程和同步的顶层S代语言,意味着程序需要在不等待获取外部资源或者耗时的使用计算的情况下一步一步的运行。如果脚本需要这样的顶层S代资源或计算,这种同步行为将导致错误。使用这会阻塞队列中的顶层S代所有其他进程运行,无论它们是使用否依赖于那些阻塞中的任务。

但很久以前,顶层S代JavaScript 引入了一个机制让其可以在等待外部资源或者耗时任务的使用时候去执行其剩余的代码。这种异步行为是顶层S代通过在函数上使用回调或 promise 来实现的。

什么是使用回调和promise

我将通过代码来解释这些概念。如果你已经知道回调和 promise 是顶层S代什么,请直接跳到顶层 await 部分和示例应用程序。使用

回调

在回调中,顶层S代一个函数作为参数传递给另一个函数;因此,使用下面 addEventListener 函数中的第二个参数是回调函数。免费源码下载此回调将等待第一个 click 事件发生,然后才执行第二个参数。 

const x = document.getElementsByTagName(Button);  x[0].addEventListener(click,() =>{alert("I was clicked")}) 

这种等待行为使代码异步。这与同步代码不同,它可以接着一步一步的运行,而不需要等待资源下载或者耗时进程结束。但要注意,并非所有回调函数都是异步的。

Promises

Promises 类似于回调,它将函数附加到返回的对象上。但Promises和回调也有不同,Promises 是专门为异步方法设计的。它们只有一个参数和一个用来获得返回结果的 then() 函数。此外,它还可以链式的附加多个.then() 和 catch() 函数。 

fetch(www.xyz.com/api)  .then((res)=>{let x = res.data; //do something with received data})  .catch((err)=>{console.log(err)}) 

Promises使用事件队列并严格遵循异步任务被链接的顺序来执行。

Async/await

Async/await 是对 Promises 的语法改进,以避免链式调用。它能使代码更清晰,更容易理解。await 关键字使代码暂停,直到 Promises 成功(resolved)或者失败(resolved)。亿华云计算 

async function asyncwaitcode(){    let getData = await axios(www.xyzdata.org/api)    console.log(getData.data)  } 

什么是顶层 await

以上所有示例都让功能块中的代码异步,没有一个在模块级工作。

但是,异步行为是可以在模块级别实现的。使用顶级 await 的模块会在异步初始化其命名空间后,再通知该模块的消费者继续执行它自己的代码。

下面的示例代码展示了如何使用顶级 await。

关于App

此应用将从新闻 API 中获取最热门的新闻数据,并在浏览器中呈现。用户还能以相关搜索词的进行新闻数据搜索。在开始之前,有几点需要注意:

 顶级await在node 13.3及更高版中被支持  顶级await只在ECMAScript模块中支持,但Node.js和Express都是CmmonJS模块。CmmonJS不支持顶级await特性。所以我在代码中会使用import而不是require  在node 14.x之前,顶级await不能直接使用,需要启用--harmony  循环引用模块可能会导致死锁

构建App

    1.  创建toplevelawait目录

$ mkdir toplevelawait 

    2.  npm init初始化

$ npm init 

    3.package.json中增加"type": "module",以支持ECMAScript模块 

"author": "",  "license": "ISC",  "type": "module", 

   4.在toplevelawait目录下创建src目录。注意使用mjs作为文件后缀名。 

$ touch app.mjs  $ touch exp.mjs  $ ls -1 src  app.mjs exp.mjs 

    5.  安装依赖axios, ejs和 express 

$ npm install axios ejs express --save 

    6.  exp.mjs中增加下面代码: 

import express from "express"  export const exp = await express(); 

注意我们是企商汇在没有async的情况下使用await。这样express实例会先初始化后再导出給其他模块。你可以用这种方式等待模块中某个实例初始化后完成后,再执行依赖于该模块的代码。

如果一个模块包含了顶层await,那么它的父模块的执行会停止,直到promise完成。但他的兄弟模块会继续执行,和以前的同步模式相同。

要注意Node.js中的模块加载也是同步的,意味着他不能异步的等待资源加载。但你可以在加载或者处理资源的语句前加上await关键字来实现异步等待。

增加news APIs

这个应用使用两个免费的新闻API来获取数据。两个API支持回退依赖行为;如果一个API失败,另一个API将获取数据。这两个API都使用API密钥:

 News API[1]  GNews API[2]

在app.mjs文件中插入下面的代码。前面的目标导入axios和在exp.js被初始化的express实例。下一部分设置视图引擎,以便在浏览器中展示。 

import { exp } from "./exp.mjs";  import axios from "axios"  exp.set("view engine","ejs");  // dependency fall back  let response = "";  let site = true;  try{     response = await axios(https://newsapi.org/v2/top-headlines?country=us&apiKey=your-api-key);     }   catch{    response = await axios("https://gnews.io/api/v3/top-news?token=your-api-key");    site = false;   }   // Get top news  exp.get(/,function(req,res){    let responseresponse0 = response.data.articles      res.render(main.ejs,{response0: response0, site:site})   })   // search news  exp.get(/search, function(req,res){    res.render("searchnews.ejs")    })  exp.get(/result, async(req, res)=>{    let x = req.query.newtitlesearch;    let response1 = {}    let data = {}    try{      let url = https://newsapi.org/v2/everything?q=+x+&apiKey=your-api-key      response1 =  await axios(url);   }    catch{      let url = https://gnews.io/api/v3/search?q=+x+&token=your-api-key      response1 =  await axios(url)    }    res.render(result.ejs, {response1: response1.data.articles, site: site})    })  exp.listen(3000) 

最重要的部分是这个try catch块,使用到了顶层await来等待axios去获取数据。如果由于任何原因,axios无法从第一个API获取数据,应用将使用第二个API获取数据。一旦它从API获得数据,express可以在主页上呈现它。 

try{     response = await axios(https://newsapi.org/v2/top-headlines?country=us&apiKey=your-api-key);    }   catch{    response = await axios("https://gnews.io/api/v3/top-news?token=your-api-key");    } 

接下来提供了一个可以让用户进行搜索的路由: 

// search news  exp.get(/search, function(req,res){    res.render("../src/view/searchnews.ejs")  }) 

最后,另一个路径展示搜索结果: 

exp.get(/result, async(req,res)=>{    let x = req.query.newtitlesearch;    let response1 = {}    let data = {}    try{      let url = https://newsapi.org/v2/everything?q=+x+&apiKey=your-api-key     response1 =  await axios(url);    }    catch{      let url = https://gnews.io/api/v3/search?q=+x+&token=your-api-key      response1 =  await axios(url)    }    res.render(../src/view/result.ejs, {response1: response1.data.articles , site: site})    }) 

写前端界面

应用的最后一部分是为前端页面编写四个.ejs HTML文件。将这些文件保存在“view”文件夹中: 

//header.ejs  <!DOCTYPE html>  <head>      <title>newapiapp</title>      <link type="text/css" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" ></head><body>        <nav class="navbar navbar-default">                <div class="container-fluid">                    <div class="navbar-header">                        <a class="navbar-brand" href="#">News app</a>                    </div>                    <div class="collapse navbar-collapse">                        <ul class="nav navbar-nav navbar-right">                               <li><a href="/">Main</a></li>                                            <li><a href="/search">Search</a></li>                           </ul>                         </div>                </div>        </nav>   //main.ejs  <%include(header);%>  <%let rows = response0%>  <%let sitesiterep = site%>  <div name "container">    <div class="row text-center" style="display:flex; flex-wrap:wrap">      <% for(let i = 0; i < rows.length; i++){%>        <div class="col-md-3 col-sm-6 ">                            <div class="thumbnail" >                              <a href="<%-rows[i].url %>">                                <img src = "<%= siterep ? rows[i].urlToImage :  rows[i].url  %>">                              </a>                                                        </div>                            <div><%= rows[i].title%></div>                                       </div>          <% } %>    </div>    </div>  //searchnews.ejs  <%- include(header);%>    <h1>Search news </h1>    <form action="/result" method="Get">        <input type ="text" placeholder="news title search" name="newtitlesearch"></input>          <input type="submit" placeholder="submit"></input>             </form>  //result.ejs  <%- include(header);%>  <%let rows = response1%>  <%let sitesiterep = site%>  <div name "container">    <div class="row text-center" style="display:flex; flex-wrap:wrap">      <% for(let i = 0; i < rows.length; i++){%>        <div class="col-md-3 col-sm-6 ">                            <div class="thumbnail" >                              <a href="<%-rows[i].url %>">                                <img src = "<%= siterep ? rows[i].urlToImage :  rows[i].url  %>">                              </a>                                                     </div>                            <div><%= rows[i].title%></div>                                           </div>         <% } %>    </div>    </div> 

运行app

现在APP已经完成,你可以尝试下。

如果你在使用node.js v13.3 至 v14.0,运行: 

$ node --harmony-top-level-await app.js 

如果你在使用node.js v14.0以上,你不需要--harmony flag: 

$ node app.js 

如果你成功构建了这个app,那么恭喜你又学会了一个新的js特性。

你可以在 ECMAScript TC39 top-level await提案[3] 中获得更多的信息。 

  • Tag:

相关文章

  • HTCOneMax拍照表现如何?(探索HTCOneMax相机的功能与性能)

    摘要:HTCOneMax作为HTC旗下一款知名智能手机,其相机表现一直备受关注。本文将深入探讨HTCOneMax相机的功能与性能,从而帮助读者更好地了解和利用这一强大的拍摄工具。...
    2025-11-05
  • 分享九个一般人不知道的Python好用技巧

    本篇分享是Python生态系统中关于一些有用的技巧。大多数技巧只是使用标准库中的包,但其他一些技巧会涉及一些第三方包。在开始阅读本文内容之前,我们首先来回顾一下Python中的Iterables的概念
    2025-11-05
  • 购买域名如何谈判价格?

    购买域名是建立在线业务的第一步,但许多企业主在购买域名时常常面临一个棘手的问题:如何谈判价格。域名的价格可能因多种因素而异,包括域名的受欢迎程度、长度、关键词以及卖家的心理预期。以下是一些有效的谈判技
    2025-11-05
  • Java中List排序的三种方法!

    作者 | 王磊来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)在某些特殊的场景下,我们需要在 Java 程序中对 List 集合进行排序操作。比如从第
    2025-11-05
  • 《穿越火线电脑玩家操作指南》(打造最强战士,征服战场!)

    摘要:穿越火线是一款备受喜爱的在线射击游戏,对于电脑玩家而言,熟练的操作是取得胜利的关键。本文将为大家提供一份详尽的电脑玩穿越火线操作教程,帮助大家提升技术、打造最强战士。1...
    2025-11-05
  • MySQL到底是如何做到多版本并发的?

    之前的文章简单的介绍了 MySQL 的事务隔离级别,它们分别是:读未提交、读已提交、可重复读、串行化。这篇文章我们就来探索一下 MySQL 事务隔离级别的底层原理。本篇文章针对 InnoDB 存储引擎
    2025-11-05

最新评论