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 获取商品"),后一个操作的回调必须嵌套在前一个操作的回调中。随着依赖步骤增加,嵌套层级会越来越深,形成 "地狱"。

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

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

javascript 复制代码
// 模拟异步操作:获取用户
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 对象)。
javascript 复制代码
// 模拟"读取文件"的异步操作(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?)
  • 作用:处理 fulfilledrejected 状态的结果。
  • 参数:
    • 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 一致)。
javascript 复制代码
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 函数:

javascript 复制代码
// 函数声明
async function fn1() {}

// 函数表达式
const fn2 = async function () {};

// 箭头函数
const fn3 = async () => {};

async 函数的返回值规则

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

示例:

javascript 复制代码
async function test() {
  return 100; // 等价于 return Promise.resolve(100)
}
test().then(res => console.log(res)); // 输出:100

async 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 处理异步操作

javascript 复制代码
// 模拟一个异步请求(返回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 方法):

示例:处理异步错误

javascript 复制代码
function riskyTask() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error("操作失败!")); // 模拟失败
    }, 1000);
  });
}

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

handleTask();

与 Promise 链式调用的对比

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

Promise 链式调用

javascript

运行

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

    运行

    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实现异步。

html 复制代码
<!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>
相关推荐
崔庆才丨静觅22 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax