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>
相关推荐
Holin_浩霖3 小时前
mini-react 动态渲染复杂的DOM结构
前端
超绝大帅哥3 小时前
你不知道的javascript学习心得
前端
小皮虾3 小时前
告别胶水代码!一行命令,让你的小程序云函数实现API路由自动化
前端·rpc·小程序·云开发
BLOOM3 小时前
一款注解驱动的axios工具
javascript·typescript
Revol_C3 小时前
【Element Plus】升级版本后,el-drawer自定义的关闭按钮离奇消失之谜
前端·css·vue.js
烟袅3 小时前
小程序开发入门:从结构到事件,快速掌握核心要点
前端·微信小程序
caicai_lf_niuniu3 小时前
🌳 ComboTreeV2:高性能虚拟树
前端·vue.js
BLOOM3 小时前
新一代前端数据mock工具Data Faker
前端·javascript
UIUV3 小时前
微信小程序开发学习笔记:从架构到实战
前端·javascript·前端框架