首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Ark 异步任务,Promise,async/await

Ark 异步任务,Promise,async/await

作者头像
誉天教育
发布2025-07-29 15:53:35
发布2025-07-29 15:53:35
1980
举报
文章被收录于专栏:HarmonyOSHarmonyOS

异步任务概述

ArkTS的异步任务沿用了JavaScript和TypeScript的异步任务机制,此文章以JavaScript语言为基础讲解异步任务相关概念和使用。文章纯属个人理解有不正确的地方欢迎指正。

在学习异步任务之前,我们先对“任务”这个词下一个定义——“任务是完成某项操作要执行的一段代码”。

一个任务可能是简单的打印语句,也可以是复杂的算法处理、网络请求或 I/O 操作等。这些任务的执行时间各不相同:打印语句执行时间通常很短,而网络请求和 I/O 操作可能耗时较长。

由于 JavaScript 执行引擎是单线程的,如果按照顺序执行所有任务,耗时较长的任务可能会阻塞线程,导致整体性能下降,进而影响用户体验。

为了更高效地管理和执行这些任务,JavaScript 将要执行的任务分为同步任务和异步任务,使得JavaScript 能够在单线程环境中有效地处理耗时操作,而不阻塞主线程。

同步任务:这些是立即执行的任务,不需要等待任何条件或事件,会阻塞后续代码的执行。

异步任务:这些任务不会立即执行,而是先挂起,被推迟到未来某个时间点执行,不会阻塞后续代码的执行。

示例代码

在 ES6(ECMAScript 2015,JavaScript标准规范) 之前,JavaScript 的异步任务主要是通过如 setTimeout, setInterval, I/O 操作 等)来实现。

代码语言:txt
复制
//同步代码
console.log("Start");	

//异步任务
setTimeout(() => {
    console.log("异步任务1");
}, 0);

//异步任务
setTimeout(() => {
    console.log("异步任务2");
}, 0);

setInterval(()=>{
     console.log("异步任务3");
}, 1000)

//同步代码
console.log("End"); 

完整输出顺序:

代码语言:txt
复制
Start
End
异步任务1
异步任务2
异步任务3  (1 秒后开始循环输出)
异步任务3  (再次循环输出)
异步任务3  (继续每秒输出)

事件循环机制

异步任务之所以能够被推迟到未来的某个时间点执行,而不阻塞主线程,主要依赖于事件循环机制和任务队列来实现的。

事件循环机制:是一种调度异步任务的模型。

任务队列:任务队列是用来存储异步任务的容器,等待后续某个时间点,被事件循环调度。

下图展示了JavaScript执行引擎启动后,各个任务的执行流程。

在 ES6 之前(ECMAScript 2015,JavaScript标准规范),所有异步任务都被放在同一个任务队列中,缺乏更精细的控制,所以从ES6开始引入了宏任务和微任务对异步任务进行更精细的控制。

宏任务和微任务

从ES6开始引入了大量的新特性(包括 Promise 和 微任务)。引入微任务是为了优化任务调度,减少延迟,提高性能,可以更高效地处理一些高优先级的小任务。从此异步任务被细分为宏任务和微任务。

微任务:具有高优先级的异步任务,通常用于较短时间内的异步操作,如 Promise 等操作。

宏任务:具有较低优先级的异步任务,通常用于延迟执行或需要等待的操作,如 setTimeout 等操作。

这种任务划分和管理机制使得 JavaScript

能够在单线程环境中有效地处理异步任务,提升程序的响应性和用户体验。

JavaScript 执行引擎通过事件循环机制、宏任务队列、微任务队列在管理并执行异步任务。如下图所示

解释:

JavaScript 执行引擎启动后,开启一条主线程,按照代码顺序依次往下执行;

当执行到宏任务时,将宏任务添加到宏任务队列,等待后续事件循环调度,JavaScript主线程继续往下执行;

当执行到微任务时,将微任务添加到微任务队列,等待后续事件循环调度,JavaScript主线程继续往下执行,直到所有同步代码执行完毕;

执行完所有同步代码之后,启动事件循环,先依次执行完微任务队列中所有的微任务,直到微任务微空。

再执行一个宏任务后,判断微任务队列是否为空(因为可能有新的微任务加入到微任务队列)

如果微任务队列不为空,则继续执行微任务队列中的所有微任务,如此循环。

示例代码

代码语言:txt
复制
//同步代码
console.log("Start");	

//宏任务: 该回调函数的任务会被添加到宏任务队列
setTimeout(() => {
    console.log("宏任务1");
}, 0);

setTimeout(() => {
    console.log("宏任务2");
}, 0);

//微任务
Promise.resolve().then(() => {
    console.log("微任务1");
});

//微任务
Promise.resolve().then(() => {
    console.log("微任务2");
});

//同步代码
console.log("End"); 

输出顺序:

代码语言:txt
复制
Start
End
微任务1
微任务2
宏任务1
宏任务2

解释:

代码语言:txt
复制
- 先执行同步代码,输出: Start 和 End。
- setTimeout() 创建的宏任务回调被加入 宏任务队列。
- Promise.resolve().then() 创建的微任务回调被加入 微任务队列。
- 同步代码执行完后,开启事件循环,会执行完微任务队列中所有的微任务,输出: 微任务1、 微任务2
- 执行完微任务后,事件循环会从宏任务队列中取出任务执行,输出: 宏任务1、宏任务2

处理异步任务的结果

前面我们学习了什么是异步任务以及其执行机制,了解到异步任务的一个重要特点是:“异步任务不会立即执行,并且不会阻塞主线程,它将在所有同步代码执行完毕后再开始执行。”然而,这种特性也引发了一个新的问题。

异步任务通常涉及耗时操作,如网络请求、文件读取等,这些操作的完成时间取决于具体的需求和运行环境的状态(如网络状况、设备性能等)。在实际开发中,我们经常需要根据异步操作的执行结果(成功或失败)来决定接下来的操作。

然而,由于异步操作在未完成之前无法获知其状态,也无法预测它具体会花费多长时间。因此,在异步任务执行过程中,我们无法直接处理后续逻辑。为了避免在等待过程中阻塞其他任务,我们需要一种机制,能够在异步任务执行完成后,根据其结果(成功或失败)来决定后续操作。无论异步任务执行成功还是失败,我们必须在编写代码时提前定义好这些处理逻辑,这样程序在执行时,才能根据任务的结果自动调用预设的处理方式。

Promise 是一种用于处理异步操作的 JavaScript 对象。它代表一个未来可能完成(或失败)的操作及其结果值。

Promise 是一种用于处理微任务的工具,同时Promise也是一个对象,它有三种状态:pending(待定)、fulfilled(已完成)和 rejected(已拒绝)。这些状态决定了 Promise 对象如何处理异步任务的结果。

pending(待定):

这是 Promise 对象的初始状态,表示异步操作还没有完成。这个状态下,Promise 既没有成功也没有失败。

fulfilled(已完成):当异步操作成功完成时,Promise 会从 pending 状态变为 fulfilled 状态。成功时调用 resolve(),并且 resolve() 的参数会作为后续 .then() 方法的回调函数的参数。

rejected(已拒绝):当异步操作失败时,Promise 会从 pending 状态变为 rejected 状态。失败时调用 reject(),并且 reject() 的参数会作为后续 .catch() 方法的回调函数的参数。

⚠️ 注意:Promise 对象一旦从 pending 状态转换为 fulfilled 或 rejected,就会被锁定在这个状态,无法再改变状态。也就是说,Promise 一旦被 resolve 或 reject,它的状态就不会再发生变化。

创建Promise对象

Promise 是一个对象,它封装了异步操作的最终结果,并提供了两种回调函数来处理成功和失败的情况。这两个回调函数分别是:

  • resolve:表示异步操作成功时调用的回调函数。
  • reject:表示异步操作失败时调用的回调函数。
代码语言:txt
复制
const promise = new Promise((resolve, reject) => {
    // 模拟异步操作
    let success = true;
    
    if (success) {
        resolve("操作成功!");
    } else {
        reject("操作失败!");
    }
}); 

在上述代码中,promise 对象的状态会根据 success 的值变为 fulfilled 或 rejected。

使用 .then() 和 .catch() 处理结果

一旦 Promise 的状态改变,你可以使用 .then() 来处理成功的结果,使用 .catch() 来处理失败的原因。

then():用来指定当 Promise 成功完成时需要执行的回调函数。

catch():用来指定当 Promise 失败时需要执行的回调函数。

代码语言:txt
复制
promise
    .then(result => {
        console.log(result);  // "操作成功!"
    })
    .catch(error => {
        console.log(error);  // "操作失败!"
    });

链式调用

当你调用 then() 或者catch() 方法时,你可以传入一个回调函数,这个回调函数会在 Promise 状态变为 fulfilled或者reject 时执行。这个回调函数可以返回一个普通值,也可以返回一个新的 Promise。

如果回调函数返回一个普通值,该值会被包装成一个 resolved 状态的 Promise,并传递到下一个 then() 方法中。

如果回调函数返回一个 Promise 对象,那么下一个 then() 将会等待这个新的 Promise 完成后再继续执行。

这使得你可以链式处理异步操作,并且 then() 方法始终返回一个新的 Promise,从而可以继续使用 .then() 进行链式调用。

示例1:回调函数返回一个普通值

在这个例子中,then() 回调函数返回了一个普通值 “World”。这个值被自动包装为一个已解决的 Promise,然后传递给下一个 .then() 回调函数。

代码语言:txt
复制
new Promise((resolve, reject) => {
    resolve("Hello");
})
    .then(result => {
        console.log(result);  // 输出 "Hello"
        return "World";  // 返回一个普通值,自动风作为resolved("World")状态的Promise对象
    })
    .then(result => {
        console.log(result);  // 输出 "World"
    });

示例 2:回调函数返回一个 Promise

在这个例子中,then() 回调函数返回了一个新的 Promise 对象。下一个 then() 会等待这个 Promise 被解析(resolve(“World”))之后,再继续执行回调。

代码语言:txt
复制
new Promise((resolve, reject) => {
    resolve("Hello");
})
    .then(result => {
        console.log(result);  // 输出 "Hello"
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("World");
            }, 1000);
        });  // 返回一个新的 Promise
    })
    .then(result => {
        console.log(result);  // 输出 "World"(等待 1 秒)
    });

异常捕获

你可以在链式调用中使用 .catch() 来捕获和处理任何一步操作中的错误。即使在链中的某个 .then() 发生了错误,错误会被传递到 .catch() 中。

触发 catch 的方式有下面几种情况:

触发 catch 的方式有下面几种情况:

当Promise处于pending状态时,手动调用 reject(),将 Promise 设为 rejected 状态, 触发catch;

当Promise处于fulfilled状态时,通过返回一个被拒绝的 Promise,它会导致 Promise 进入 rejected 状态,从而触发 catch。

主动通过throw抛出异常,会让当前的异步操作失败,从而触发 catch

示例1:当Promise处于pending状态时,throw抛出异常,触发catch

代码语言:txt
复制
new Promise((resolve, reject) => {
    throw new Error("Something went wrong");
})
    .catch(error => {
        console.log(error.message);  // 输出 "Something went wrong"
    });

示例2:当Promise处于fulfilled状态时,throw抛出异常,触发catch

代码语言:txt
复制
new Promise((resolve, reject) => {
    resolve("Success")
})
  .then(result=>{
     console.log(result);	//Success
     throw new Error("出错了。。。")
  })
  .catch(error => {
      console.log(error); //出错了。。。
  });

示例3:当Promise处于fulfilled状态时,返回一个被拒绝的Promise,触发catch

代码语言:txt
复制
new Promise((resolve, reject) => {
    resolve("Success")
})
  .then(result=>{
     console.log(result);	//Success
     return new Promise((resolve,reject)=>{
        reject("Failed。。。")
     })
  })
  .catch(error => {
      console.log(error); //Failed。。。
  });

Promise 快捷操作

Promise.resolve()

Promise.resolve() 是一个用于快速创建已解决的 Promise 对象的工具方法,能够处理普通值、Promise 对象。

代码语言:txt
复制
// value:可以是任意值,也可以是一个 Promise 对象。
Promise.resolve(value); 

如果value传入的值已经是一个 Promise,则直接返回该 Promise;如果传入的值是一个普通值(如字符串、数字等),则返回一个已解决的 Promise,并将该值作为结果传递给 then() 的回调函数。

示例1:传入普通值

代码语言:txt
复制
//Promise.resolve(42) 返回一个已经解决的 Promise,并将 42 作为结果传递给 then() 回调。
const promise = Promise.resolve(42);
promise.then(result => {
    console.log(result);  // 输出 42
});

示例2:传入另一个已解决的 Promise

代码语言:txt
复制
const existingPromise = Promise.resolve("Hello, World!");
// 直接返回传入的 existingPromise,因为它已经是一个 Promise,所以不会创建新的 Promise。
const promise = Promise.resolve(existingPromise);

promise.then(result => {
    console.log(result);  // 输出 "Hello, World!"
});
Promise.rejected()

与 Promise.resolve() 类似,Promise.reject() 用于快速创建一个被拒绝的 Promise,并且可以传递拒绝的原因。

代码语言:txt
复制
//reason:拒绝的原因,可以是任意类型的值(通常是一个错误对象或错误消息),它将作为 catch() 方法的回调函数的参数。
Promise.reject(reason);

Promise.reject() 返回一个 Promise 对象,它的状态被立即设置为 rejected,并将传入的拒绝原因作为参数传递给 catch() 回调函数。

示例1: 返回一个已经拒绝的Promise

这里,Promise.reject(“Something went wrong”) 返回一个已拒绝的 Promise,并将 “Something went wrong” 作为错误原因传递给 catch() 方法。

代码语言:txt
复制
const promise = Promise.reject("Something went wrong");
promise.catch(error => {
    console.log(error);  // 输出 "Something went wrong"
});

示例2:返回一个已拒绝的 Promise,拒绝原因为 Error 对象

这里,Promise.reject(new Error(“Network Error”)) 返回一个已拒绝的 Promise,并将 Error 对象传递给 catch() 方法。catch() 中可以通过 error.message 获取错误的具体信息。

代码语言:txt
复制
const promise = Promise.reject(new Error("Network Error"));
promise.catch(error => {
    console.log(error.message);  // 输出 "Network Error"
});

示例3:链式调用中的错误传播

在 Promise 链中的任何一个 Promise 被拒绝时,后续的 catch() 会捕获到该错误,即使该拒绝发生在链中的任意一环。

代码语言:txt
复制
Promise.resolve("Start")
    .then(result => {
        console.log(result);
        return Promise.reject("Error occurred");
    })
    .catch(error => {
        console.log(error);  // 输出 "Error occurred"
    });

本文来源誉天王琦老师编写!

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 创建Promise对象
  • Promise 快捷操作
    • Promise.resolve()
    • Promise.rejected()
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档