JavaScript 是一种流行的编程语言,最初被设计为单线程和同步的语言,意味着程序需要在不等待获取外部资源或者耗时的计算的情况下一步一步的运行。如果脚本需要这样的资源或计算,这种同步行为将导致错误。这会阻塞队列中的所有其他进程运行,无论它们是否依赖于那些阻塞中的任务。
专注于为中小企业提供成都网站建设、做网站服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业会昌免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了超过千家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
但很久以前,JavaScript 引入了一个机制让其可以在等待外部资源或者耗时任务的时候去执行其剩余的代码。这种异步行为是通过在函数上使用回调或 promise 来实现的。
什么是回调和promise
我将通过代码来解释这些概念。如果你已经知道回调和 promise 是什么,请直接跳到顶层 await 部分和示例应用程序。
回调
在回调中,一个函数作为参数传递给另一个函数;因此,下面 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 中获取最热门的新闻数据,并在浏览器中呈现。用户还能以相关搜索词的进行新闻数据搜索。在开始之前,有几点需要注意:
构建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密钥:
在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
newapiapp
- //main.ejs
- <%include('header');%>
- <%let rows = response0%>
- <%let sitesiterep = site%>
- //searchnews.ejs
- <%- include('header');%>
Search news
- //result.ejs
- <%- include('header');%>
- <%let rows = response1%>
- <%let sitesiterep = site%>
运行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] 中获得更多的信息。
网站题目:使用顶层await简化JS代码
网站URL:http://www.gawzjz.com/qtweb/news9/202309.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联