异步 “一发入魂“

异步

概述:

异步就是从主线程发射一个子线程来完成任务

img

什么时候用异步编程

主线程作为一个线程,不能够同时接受多方面的请求。所以,当一个事件没有结束时,界面将无法处理其他请求。

为了避免这种情况的发生,我们常常用子线程来完成一些可能消耗时间足够长以至于被用户察觉的事情,

比如读取一个大文件或者发出一个网络请求。因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。但是子线程有一个局限:一旦发射了以后就会与主线程失去同步,我们无法确定它的结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。

为了解决这个问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。

回调函数

回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:

等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。

function print() {
    document.getElementById("demo").innerHTML="RUNOOB!";
}
setTimeout(print, 3000);

这段程序中的 setTimeout 就是一个消耗时间较长(3 秒)的过程,它的第一个参数是个回调函数第二个参数毫秒数,这个函数执行之后会产生一个子线程,子线程会等待 3 秒,然后执行回调函数 “print”,在命令行输出 “RUNOOB!”

也可以直接写成:

setTimeout(function () {
    document.getElementById("demo").innerHTML="RUNOOB!";
}, 3000);

这样就实现了我们的子线程等待3秒才执行,但不耽搁我们的主线程执行

setTimeout(function () {
    document.getElementById("demo1").innerHTML="RUNOOB-1!";  // 三秒后子线程执行
}, 3000);
document.getElementById("demo2").innerHTML="RUNOOB-2!";      // 主线程先执行

img

Promise

概述:

Promise 是一种用于处理异步操作的对象。Promise 表示一个操作的最终完成(或失败)及其结果值

通过 new Promise 来创建一个 Promise 实例。

它接受一个执行函数,该函数包含两个参数:resolvereject

resolve 用于将 Promise 的状态变为已完成,并传递结果;

reject 用于将状态变为已拒绝,并传递错误。

function aa(){
  const promise:Promise<string> = new Promise((resolve, reject) => {
    // 异步操作
    setTimeout(() => {
      if (Math.random() < 0.5) {
        resolve('success');
      } else {
        reject('error');
      }
    }, 1000);
  });
//获取返回值
  promise.then(result => {
    console.log('aa',result);
  }).catch((err:BusinessError)=>{
    console.log('aa',err);
  });
}

上面的例子中,我们使用 Promise 构造函数创建了一个 Promise 对象,并使用 setTimeout 模拟了一个异步操作。

1、如果异步操作成功,则调用 resolve 函数并传递成功的结果

2、如果异步操作失败,则调用 reject 函数并传递失败的原因。

3、然后我们使用 then 方法处理 Promise 成功状态的回调函数使用 catch 方法处理 Promise 失败状态的回调函数

这段程序会直接输出 errorsuccess

resolve 和 reject 都是函数,其中调用 resolve 代表一切正常reject 是出现异常时所调用

回答常见的问题(FAQ)

Q: then、catch 和 finally 序列能否顺序颠倒?

A: 可以,效果完全一样。但不建议这样做,最好按 then-catch-finally 的顺序编写程序。

Q: 除了 then 块以外,其它两种块能否多次使用?

A: 可以,finally 与 then 一样会按顺序执行,但是 catch 块只会执行第一个,除非 catch 块里有异常。所以最好只安排一个 catch 和 finally 块。

Q: then 块如何中断?

A: then 块默认会向下顺序执行,return 是不能中断的,可以通过 throw 来跳转至 catch 实现中断。

Q: 什么时候适合用 Promise 而不是传统回调函数?

A: 当需要多次顺序执行异步操作的时候,例如,如果想通过异步方法先后检测用户名和密码,需要先异步检测用户名,然后再异步检测密码的情况下就很适合 Promise。

Q: Promise 是一种将异步转换为同步的方法吗?

A: 完全不是。Promise 只不过是一种更良好的编程风格。

Q: 什么时候我们需要再写一个 then 而不是在当前的 then 接着编程?

A: 当你又需要调用一个异步任务的时候。

Promise 类有 .then() .catch() 和 .finally() 三个方法,

这三个方法的参数都是一个函数,

.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,

.catch() 则是设定 Promise 的异常处理序列,

.finally() 是在 Promise 执行的最后一定会执行的序列。

.then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列:

new Promise(function (resolve, reject) {
    console.log(1111);
    resolve(2222);
}).then(function (value) {
    console.log(value);
    return 3333;
}).then(function (value) {
    console.log(value);
    throw "An error";
}).catch(function (err) {
    console.log(err);
});

写一个方法测试一下:

//传入两个参数一个延时时间,一个打印的日志
function cc(delay:number, message:string) {
  const  promise:Promise<string>=new Promise((resolve, reject)=> {
    setTimeout(()=> {
      console.log('ccc',message);
      resolve('123');
    }, delay);
  });
  return promise.then(result => {
    console.log('ccc',result);
  });
    .catch((err:BusinessError)=>{
      console.log('ccc',err)
    });
}

如果用普通方式写一直调用.then属性

print(1000, "First")
    .then(function () {
    	return print(4000, "Second");
	})
    .then(function () {
   		 print(3000, "Third");
	});

这时候我们就可以用acync await更加简洁

async function asyncFunc() {
    await print(1000, "First");
    await print(4000, "Second");
    await print(3000, "Third");
}

//再调用该方法
asyncFunc();

异步函数 async function 中可以使用 await 指令,await 指令后必须跟着一个 Promise,异步函数会在这个 Promise 运行中暂停,直到其运行结束再继续运行。

异步函数实际上原理与 Promise 原生 API 的机制是一模一样的,只不过更便于程序员阅读。

处理异常的机制将用 try-catch 块实现:

//js
async function asyncFunc() {
    try {
        await new Promise(function (resolve, reject) {
            throw "Some error"; // 或者 reject("Some error")
        });
    } catch (err) {
        console.log(err);
        // 会输出 Some error
    }
}

//ArkTs
async function asyncFunc1() {
  try {
    await Promise.reject('报错信息')
  } catch (err) {
    console.log('asyncFunc1',err);
    // 会输出 ‘报错信息’
  }
}

//方法调用
asyncFunc();

image-20240904002346310

如果 Promise 有一个正常的返回值,await 语句也会返回它:

/*js里面是这样写的
 * async function asyncFunc() {
    let value = await new Promise(
        function (resolve, reject) {
            resolve("Return value");
        }
    );
    console.log(value);
}
 */

//arkTs是这样写的
async function asyncFunc() {
  const result = await Promise.resolve('hello world');
  console.log(result);
}

//调用使用
asyncFunc()

image-20240904002356070
文章来源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lucky me.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值