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

Harmony鸿蒙开发0基础入门到精通Day11--TypeScript篇

JavaScript到这里,我们的JS部分就已经结束了,接下来将会学习我们的新语言TypeScript。

TypeScript

TypeScript(简称 TS)是微软开发的一门开源编程语言,它是 JavaScript 的超集(Superset)—— 这意味着所有合法的 JavaScript 代码都是合法的 TypeScript 代码,同时 TypeScript 在 JavaScript 基础上增加了静态类型系统,并扩展了更多特性。

因为浏览器只支持js语言,所以我们需要一些组件,将编写的TS代码转化为JS在浏览器上运行。

前后端交互使用xhr,后期采取node

回调地狱

“回调地狱”(Callback Hell)是 JavaScript 异步编程中因多层嵌套的回调函数导致的代码可读性差、维护困难的现象。它的核心问题是:当多个异步操作存在依赖关系(后一个操作需要前一个的结果)时,回调函数会层层嵌套,形成 “金字塔” 式的代码结构,最终变得难以理解和修改。

为什么会出现回调地狱?

JavaScript 是单线程语言,处理异步操作(如网络请求、文件读写、定时器)时,必须通过回调函数指定操作完成后的逻辑。如果异步操作存在依赖(比如 “先获取用户信息→再用用户 ID 获取订单→再用订单 ID 获取商品”),后一个操作的回调必须嵌套在前一个操作的回调中。随着依赖步骤增加,嵌套层级会越来越深,形成 “地狱”。

典型示例:回调地狱长什么样?

假设我们需要模拟三个依赖的异步操作,用嵌套回调实现会是这样:

// 模拟异步操作:获取用户
function getUser(userId, callback) {setTimeout(() => {console.log("1. 获取用户信息成功");callback({ id: userId, name: "小明" }); // 回调传递用户数据}, 1000);
}// 模拟异步操作:用用户ID获取订单
function getOrder(userId, callback) {setTimeout(() => {console.log("2. 根据用户ID获取订单成功");callback({ orderId: "order_001", userId }); // 回调传递订单数据}, 1000);
}// 模拟异步操作:用订单ID获取商品
function getProduct(orderId, callback) {setTimeout(() => {console.log("3. 根据订单ID获取商品成功");callback({ productId: "prod_123", orderId }); // 回调传递商品数据}, 1000);
}// 多层嵌套的回调(回调地狱)
getUser(101, (user) => {getOrder(user.id, (order) => {getProduct(order.orderId, (product) => {console.log("最终结果:", product);// 如果还有更多步骤,这里会继续嵌套...});});
});

这段代码的问题:

  • 层级过深(像 “金字塔” 一样向右延伸),阅读时需要逐层查找逻辑。
  • 维护困难:修改某一步逻辑时,需要在多层嵌套中定位。
  • 错误处理繁琐:每个回调都要单独处理错误,容易遗漏。

如何解决回调地狱?

核心思路是避免嵌套,让代码 “纵向扁平”,用 Promise 链式调用替代嵌套。

Promise

Promise 代表一个尚未完成但最终会有结果的异步操作(如网络请求、文件读写、定时器等)。它有且仅有三种状态,且状态一旦改变就不可逆

  • pending(等待中):初始状态,异步操作尚未完成。
  • fulfilled(已成功):异步操作完成,结果可用(由 resolve 触发)。
  • rejected(已失败):异步操作出错,原因可用(由 reject 触发)。

基本用法:创建与使用 Promise

通过 new Promise(executor) 创建实例,executor 是一个立即执行的函数,接收两个参数:

  • resolve(value):异步成功时调用,将状态转为 fulfilled,并传递结果 value
  • reject(error):异步失败时调用,将状态转为 rejected,并传递错误 error(通常是 Error 对象)。
// 模拟“读取文件”的异步操作(1秒后随机成功/失败)
const readFilePromise = new Promise((resolve, reject) => {setTimeout(() => {const success = Math.random() > 0.3; // 70% 概率成功if (success) {resolve("文件内容:Hello World"); // 成功时传递结果} else {reject(new Error("文件不存在")); // 失败时传递错误}}, 1000);
});

处理异步结果

Promise 实例通过以下方法定义状态改变后的逻辑,且这些方法返回新的 Promise,因此支持链式调用

1. then(onFulfilled?, onRejected?)
  • 作用:处理 fulfilled 或 rejected 状态的结果。
  • 参数:
    • onFulfilled:状态为 fulfilled 时执行,接收 resolve 传递的 value
    • onRejected:状态为 rejected 时执行,接收 reject 传递的 error(可选,通常用 catch 替代)。
  • 返回值:新的 Promise,其状态由回调函数的返回值决定(若返回 Promise,则跟随其状态;否则直接 fulfilled)。
2. catch(onRejected)
  • 作用:专门处理 rejected 状态,等价于 then(null, onRejected)
  • 优势:更清晰地集中捕获错误(包括 then 回调中抛出的错误)。
3. finally(onFinally)
  • 作用:无论状态是 fulfilled 还是 rejected,都会执行(如关闭加载动画、清理资源)。
  • 特点:不接收参数(无法获取成功 / 失败的结果),返回新的 Promise(状态与原 Promise 一致)。
readFilePromise.then((content) => {console.log("读取成功:", content);return content.toUpperCase(); // 返回处理后的值,传给下一个then}).then((upperContent) => {console.log("转换为大写:", upperContent); // 输出:读取成功的内容的大写形式}).catch((error) => {console.log("出错了:", error.message); // 捕获所有上游错误(如“文件不存在”)}).finally(() => {console.log("操作结束(无论成败)"); // 必然执行});

async/await 

async/await 是 ES2017(ES8)引入的语法糖,基于 Promise 实现,用于简化异步代码的编写。它让异步逻辑的写法更接近同步代码,解决了 Promise 链式调用可能带来的代码冗余问题,进一步提升了可读性和可维护性。

核心作用

  • async:修饰函数,表明该函数内部有异步操作,函数的返回值会自动包装为一个 Promise(无论是否显式返回 Promise)。
  • await:只能在 async 函数内部使用,用于 “等待” 一个 Promise 完成,暂停当前函数执行,直到 Promise 状态变为 fulfilled(成功)或 rejected(失败),再继续执行后续代码。

基本用法

1. async 函数的定义

在函数声明、函数表达式、箭头函数前添加 async 关键字,即可定义一个 async 函数:

// 函数声明
async function fn1() {}// 函数表达式
const fn2 = async function () {};// 箭头函数
const fn3 = async () => {};

async 函数的返回值规则

  • 若返回非 Promise 值(如 123{a:1}),则自动包装为 Promise.resolve(返回值)
  • 若返回 Promise,则直接返回该 Promise(状态由其自身决定)。
  • 若抛出错误(throw new Error(...)),则自动包装为 Promise.reject(错误)

示例:

async function test() {return 100; // 等价于 return Promise.resolve(100)
}
test().then(res => console.log(res)); // 输出:100async function test2() {throw new Error("出错了"); // 等价于 return Promise.reject(new Error("出错了"))
}
test2().catch(err => console.log(err.message)); // 输出:出错了
2. await 的使用

await 后必须跟一个 Promise 对象(若不是,会自动用 Promise.resolve() 包装),作用是 “等待” 该 Promise 完成:

  • 若 Promise 成功(fulfilled),await 会返回 Promise 的结果(resolve 的值)。
  • 若 Promise 失败(rejected),await 会抛出错误(需用 try/catch 捕获)。

示例:用 async/await 处理异步操作

// 模拟一个异步请求(返回Promise)
function fetchData() {return new Promise((resolve) => {setTimeout(() => {resolve({ name: "张三", age: 20 });}, 1000);});
}// 用async/await调用异步函数
async function getUser() {// 等待fetchData的结果(1秒后返回)const user = await fetchData(); console.log(user); // 输出:{ name: "张三", age: 20 }(1秒后执行)return user;
}getUser();

错误处理

await 等待的 Promise 若失败(rejected),会抛出错误,需用 try/catch 捕获(替代 Promise 的 catch 方法):

示例:处理异步错误

function riskyTask() {return new Promise((resolve, reject) => {setTimeout(() => {reject(new Error("操作失败!")); // 模拟失败}, 1000);});
}async function handleTask() {try {// 等待可能失败的Promiseconst result = await riskyTask(); console.log("成功:", result); // 若成功则执行(此处不会执行)} catch (error) {// 捕获失败的错误console.log("失败:", error.message); // 输出:失败:操作失败!}
}handleTask();

与 Promise 链式调用的对比

async/await 本质是 Promise 的语法糖,但比链式调用更直观。

Promise 链式调用

javascript

运行

fetchUser().then(user => fetchOrder(user.id)).then(order => fetchProduct(order.id)).then(product => console.log(product)).catch(err => console.log(err));
  • async/await 写法

    javascript

    运行

    async function getResult() {try {const user = await fetchUser();const order = await fetchOrder(user.id);const product = await fetchProduct(order.id);console.log(product);} catch (err) {console.log(err);}
    }
    getResult();
    

显然,async/await 的代码更接近同步逻辑,层级扁平,可读性更高。

node.js的安装

https://nodejs.org/zh-cn/download/

进入网址后,按照步骤一步步安装即可,不要下载最新版就行。

数据请求

在编程中,“数据请求” 通常指通过网络(如 HTTP/HTTPS)从服务器获取或提交数据(如 API 接口调用)。不同环境(浏览器 / Node.js)有不同的实现方式。

数据请求的核心目的

前端发起数据请求,本质是通过 HTTP/HTTPS 协议与后端接口通信,获取后端存储的数据(如你的商品列表、用户信息),或提交前端数据(如表单、订单),最终服务于业务逻辑(如渲染商品、展示用户信息)。

核心特点:异步性(请求需要时间,不会阻塞前端代码执行,必须通过特定方式处理结果)。

我们使用一个京东案例,采用原生Ajax实现异步。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<style>* {padding: 0;margin: 0;}html,body {background-color: #F5F6FA;/* height: 100%; */width: 100%;display: flex;/* align-items: center; *//* border: 1px solid black; */display: flex;flex-direction: column;}.divtop {-webkit-font-smoothing: antialiased;font: 12px/1.5 PingFang SC, Source Han Sans CN, Microsoft YaHei, Heiti SC, tahoma, arial, Hiragino Sans GB, "\5B8B\4F53", sans-serif;margin: 0;padding: 0;color: #666;text-decoration: none;width: 100%;/* cursor: pointer; */display: block;background-color: rgb(255, 63, 75);height: 60px;text-align: center;}.app {display: flex;flex-wrap: wrap;justify-content: center;/* align-items: center; */background-color: white;}.just {display: flex;flex-direction: column;/* justify-content: center; *//* align-items: center; *//* height: 100%; */width: 15%;padding: 5px;}.just:hover {border: 2px red solid;border-radius: 10px;cursor: pointer;}.content {width: 100%;overflow: hidden;/* 必须:隐藏超出的行 */text-overflow: ellipsis;/* 最后一行末尾显示省略号 */display: -webkit-box;/* 开启弹性盒模型(用于多行控制) */-webkit-line-clamp: 2;/* 限制最大显示行数(关键) */-webkit-box-orient: vertical;/* 垂直排列文本(关键) */padding: 0 2px;/* 可选:长单词/长数字换行 */word-break: break-all;font-size: 16px;}.t,.s {font-size: 14px;color: gray;}.p {font-weight: bold;font-size: 18px;color: red;}.item {position: relative;}.i2 {position: absolute;right: 0;top: 0;}.s:hover {color: red;}ul {display: flex;list-style: none;}li {padding: 5px;}.divtop2 {height: 30px;font-size: 14px;color: #666;display: flex;justify-content: space-between;}ul :hover {color: red;cursor: pointer;/* text-decoration: underline; */}.divtop2 ul li:nth-child(1) {position: relative;}.divtop2 ul li:nth-child(1):hover .city {display: block;}.city {position: absolute;/* background-color: yellow; */background-color: #fff;height: 100px;width: 100px;z-index: 1;font-size: 14px;color: #000;display: none;}.city span:hover {background-color: red;color: #fff;width: 100%;}
</style><body><div class="divtop"><img width="10%"src="https://img20.360buyimg.com/img/jfs/t1/339448/9/18317/1603/68e931c0F85a2f55c/6d0a0e2999849996.png"alt=""><img width="65%" src="./img/2.png" alt=""></div><div class="divtop2"><div class="left"><ul><li><div>中国大陆-北京</div><div class="city"><span>中国大陆版</span><br><span>中國港澳版</span><br><span>中國台灣版</span><br><span>京东全球版</span></div></li><li>你好,先登录<span style="margin-left: 10px;color: red;">免费注册</span></li><li>切换企业版</li></ul></div><div class="right"><ul><li>购物车</li><li>我的订单</li><li>我的京东</li><li>企业采购</li><li>商家服务</li><li>网页导航</li><li>手机京东</li><li>网站无障碍</li></ul></div></div><div class="app"><!-- <div class="just"> --><!-- <div class="item"><img width="100%" src="https://ts1.tc.mm.bing.net/th/id/OIP-C.P1sp8dyDEIRwTuSVCbReiQAAAA?rs=1&pid=ImgDetMain&o=7&rm=3" alt=""></div><div class="item">描述</div><div class="item">标签</div><div class="item">价格</div><div class="item">店铺</div></div> --><!-- </div> -->
</body>
<script>//let xhr = new XMLHttpRequest()xhr.open('get', "http://localhost:8889/data", true)xhr.send()xhr.onreadystatechange = () => {if (xhr.readyState == 4 && xhr.status == 200) {// console.log(xhr.responseText);let jds = JSON.parse(xhr.responseText)// console.log(jds);jds.myData.jds.forEach(element => {document.querySelector('.app').innerHTML += `<div class="just"><div class="item i"><img width="100%" src="${element.img}" alt=""><img class="i2" width="20%" src="https://m.360buyimg.com/umm/jfs/t1/344271/40/7695/1784/68d666cfF0a0873a3/2666ed87fae11ac8.png" alt=""></div><div class="item content">${element.content}</div><div class="item t">${element.title}</div><div class="item p">¥${element.price}</div><div class="item s">${element.store}</div></div></div>`});}}
</script></html>

http://www.dtcms.com/a/568984.html

相关文章:

  • 网站做广告的好处软件定制开发平台
  • 从智能手表拆解看硬件与软件的魔法融合 -嵌入式开发
  • 【java基础语法】---- 综合训练
  • BKA-Transformer-LSTM多变量时间序列预测Matlab实现
  • 如何自己创造一个网站平台搬瓦工装WordPress
  • 数式Oinone亮相GOTC 2025开源集市,企业级产品化引擎冲击Gitee当日热门项目
  • 【产品研究】生物力学软件 SIMM 4.0 for Windows 用户手册总结
  • 更新公司网站内容需要山东住房和城乡建设局网站首页
  • Unity与Android原生交互开发入门篇 - 打开Android的设置
  • 如何查看Linux系统版本?
  • Python类和对象--生命周期方法(对象生命周期,内存管理机制-存储,垃圾回收)
  • PAIMON+STARROCKS 学习
  • *曲速引擎的核心思想
  • AI时代下医药项目管理效能提升与知识管理案例分享︱奥锐特药业研发中心主任庄守群
  • 路由器构建园区网
  • 陕西建设网站如何建立免费网站
  • 设计网站账号品牌策划公司广告语
  • 二十一、kubernetes 1.29 之 运维 03
  • 【论文精读】CMD:迈向高效视频生成的新范式
  • 技术实践 | 延趣游戏用户分层体系:基于TE系统实现精细化运营与流水增长
  • 【硬件SDK项目】uniapp框架设计与业务开发
  • 做推广必须知道的网站淮南网络建站公司
  • tcp 丢包分析
  • 基于改进Gerchberg–Saxton算法的全息图相位恢复方法研究
  • 【ISO8601】ISO8601 Rust 库完整学习指南
  • 辽宁沈阳做网站贷款公司网站模板
  • 【数论】乘法逆元(求逆元的三种方式)
  • c++ 引用包装器的用法
  • ArrayList数据结构-数组篇
  • 合肥建设工程信息网站网站pc端和手机端分离怎么做