js是单线程,为了不浪费时间,提高运行效率。
主要是依据settimeout(定时执行回调函数)和setinterval(定时执行回调函数并以相同间隔重复执行,可以通过clearInterval取消重复)函数。
js有一个专门处理计时器的模块。js主线程先解决同步任务,与此同时,计时器模块独立运行,将到时的任务放入异步队列,当同步任务解决完以后,js会解决到时的异步队列。
JS 异步编程进化史:callback -> promise -> generator -> async + await
回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。
ajax(url, () => {
// 处理逻辑
ajax(url1, () => {
// 处理逻辑
ajax(url2, () => {
// 处理逻辑
})
})
})
js遇到回调函数即会放入异步队列。
回调正是确保一段代码执行完毕之后再执行另一段代码的方式,可以确保函数异步执行。
回调函数优点:不会立即执行、是个闭包(可以访问到到其外层定义的变量)
回调函数是嵌套调用,外部回调函数执行结果是嵌套的回调执行的条件,不便于阅读,不便于异常处理
必须在启动异步任务之前指定所有任务
链式调用,避免了回调地域
可以在异步任务启动后绑定新的一致多个回调
resolve(value)
: pending -> resolvedreject(reson)
: pending -> rejected//promise参数为函数,该函数的参数默认有resolve、reject两个函数类型参数
new Promise((resolve,reject)=>{
//...期间的同步代码会正常执行,异步代码会正常放入该去的队列
//resolve('成功');改变后调用onResolved函数
//reject('失败');改变后调用onRejected函数
//更改完状态再将相应代码放入微队列,等待同步代码执行完后再执行
//promise和then是对应出现的,then返回的也是promise对象
//then可以一直套用下去,并且then中任务能确保异步的顺序
}).then(onResolved,onRejected);
.catch(onRejected)
.finally()
//也可以是.finally 即不论怎么样都执行 等同于.then(fn,fn)
- 通常用于常规清理
- finally 处理程序没有得到前一个处理程序的结果(它没有参数)。而这个结果被传递给了下一个合适的处理程序。
- 如果 finally 处理程序返回了一些内容,那么这些内容会被忽略。
- 当 finally 抛出 error 时,执行将转到最近的 error 的处理程序。
then(onResolved,onRejected);
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(value => {
return new Promise((resolve, reject) => {
resolve(" success" );
});
}).then(value => {//此时为一个状态为resolved,结果为success的promise调用.then
console.log(value); //success
}).then(value => {//调用者没有return,所以为默认值,为一个状态为resolved,结果为undefined的默认Promise调用
console.log(value);//undefined
})
此时状态改变遵循参数的状态而不是调用的
let p1 = new Promise((resolve, reject)=>{
reject("拒绝");
});
new Promise((resolve, reject)=>{
resolve(p1);//即遵循p1而不是resolve
}).then(
msg=>{console. log(msg);},
error=>{console. log(error+'error');
})
let p = new Promise((resolve,reject)=>{
resolve('成功')
})
//当p转变为resolve状态时,即会一次调用以下两个then
//但是如果是reject,因为then中没有指定失败的回调函数,所以不执行(没有对应执行的)
p.then(value =>{
console.log(value)
})
p.then(value =>{
console.log(value+"1")
})
catch(onRejected)
Promise.resolve(value)
Promise.reject(reason)
该方法用于多个promise实例,包装成一个新的promise实例,即等待所有promise准备就绪
Promise.all([p1,p2,p3]);
Promise.all([p1, p2]).then((result) => {
console.log(result) //['成功了', 'success']
}).catch((error) => {
console.log(error) //
})
Promise.race([p1,p2,p3]);
对于每个promise都获取了其状态和value/reason
let urls = [
'https://api.github.com/users/iliakan',
'https://api.github.com/users/remy',
'https://no-such-url'
];
Promise.allSettled(urls.map(url => fetch(url)))
.then(results => { // (*)
results.forEach((result, num) => {
if (result.status == "fulfilled") {
alert(`${urls[num]}: ${result.value.status}`);
}
if (result.status == "rejected") {
alert(`${urls[num]}: ${result.reason}`);
}
});
});
与 Promise.race 类似,区别在于 Promise.any 只等待第一个 成功的 promise,并将这个 fulfilled 的 promise 返回。如果给出的 promise 都 rejected,那么返回的 promise 会带有 AggregateError —— 一个特殊的 error 对象,在其 errors 属性中存储着所有 promise error。
异常穿透现象:只需要在最后一个then后调用catch就可以捕获所有异常
let p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('Err');
}, 1000);
});
p.then(value => {
console.log(111);
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
})
let p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('Err');
}, 1000);
});
p.then(value => {
console.log(111);
return new Promise(()=>{})
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
})
这种返回值为一个 Promise 对象的函数称作 Promise 函数,它常常用于开发基于异步操作的库。
function print(delay, message) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(message);
resolve();
}, delay);
});
}
print(1000, "First").then(function () {
return print(4000, "Second");
}).then(function () {
print(3000, "Third");
});
缺点:无法取消 Promise,错误需要通过回调函数捕获。
.then(
value > {
return new Promise((resolve,reject) = {//其后的then是对该返回值promise的处理
reject( "处理失败" );
})
.then(
null,
r =console.log(r);
});
//处理失败
new promise ((resolve,reject)=>{...})
中resolve(),reject()
,到此封装完成resolve(),reject()
的具体内容,处理结果通过此方法可以将回调函数风格简便的转换成promise风格
//引入util 模块
const util = require('util');
//引入fs模块
const fs = require('fs');
//返回一个新的函数
let mineReadFile = util. promisify(fs.readFile);
mineReadFile('./resource/content.txt'). then(value=>{ ... });|
async function main(){
try{
//读取第一个文件的内容
let datal = await mineReadFile(' ./ resource/1. html' );
let data2 = await mineReadFile(' . / resource/2. html');
let data3 = await mineReadFile(' ./resource/3.html' );
console.1og(data1 + data2 + data3);
}catch(e){ .. }
let results = await Promise.all([...]);
try{}catch{}
捕获
try{}catch{}
中写await比较保险async function f() {
await Promise.reject(new Error("Whoops!"));
}
即
async function f() {
throw new Error("Whoops!");
}
async function f() {
try {
let response = await fetch('http://no-such-url');
} catch(err) {
alert(err); // TypeError: failed to fetch
}
}
f();