异步
概述:
异步就是从主线程发射一个子线程来完成任务。
什么时候用异步编程
主线程作为一个线程,不能够同时接受多方面的请求。所以,当一个事件没有结束时,界面将无法处理其他请求。
为了避免这种情况的发生,我们常常用子线程来完成一些可能消耗时间足够长以至于被用户察觉的事情,
比如读取一个大文件或者发出一个网络请求。因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。但是子线程有一个局限:一旦发射了以后就会与主线程失去同步,我们无法确定它的结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。
为了解决这个问题,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!"; // 主线程先执行
Promise
概述:
Promise
是一种用于处理异步操作的对象。Promise
表示一个操作的最终完成(或失败)及其结果值
通过 new Promise
来创建一个 Promise 实例。
它接受一个执行函数,该函数包含两个参数:resolve
和 reject
。
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 失败状态的回调函数。
这段程序会直接输出 error 或 success。
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();
如果 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()
文章来源