第十五章 异步
任务先后执行的问题
js为单线程语言
单线程问题是阻塞,按顺序执行即前边必须执行完。
解决的是执行顺序的问题。
js
function img(src){
let img = new Img();
img.src = src
}
img("iaklsjflk/zsdlkn/121sd");
console.log("alett");
可以知道,控制台输出会在图片加载之前就进行,产生报错。
js
主任务完成后,轮询任务队列。
加载与执行
loading&excusing
先加载不一定先执行。
先执行不一定先加载
js
定时器练习
setTimeOut() 单次执行
setInterval() 反复执行
任务排序
js
函数模块永远是在主进程加载完毕后执行。
主进程再慢也得等主进程加载完毕。
function loading(src,resolve){
let script = document.createElement("script");
script.src = src;
script.onload = resolve;
document.body.appendChild(script);
}
loading("first.js",()=>{
first();
})
loading("second.js",()=>{
second();
})
console.log("main programs")
非主进程谁加载的快谁优先放入任务队列中,先进先出。
异步线程的数据可以使用主线程数据
任务请求
js
1、通过http模块请求后台数据
2、任务队列中添加任务
3、主程序执行任务,主程序执行完毕后执行任务队列中的任务
对于有文件依赖的任务,容易产生多层次回调嵌套。
产生了promise
promise
通知
js
Part1:准备阶段
new Promise((a,b)=>{}) //Promise{<pending>} 准备阶段
准备成功,用a函数通知;准备失败,用b函数通知。
js
Part2:处理阶段
~.then(a,b)
a,处理成功的回调;b,处理失败的回调
js
以微任务队列为主
如果微任务队列有任务,会优先执行微任务队列
Promise产出微任务队列。
微任务队列执行完毕后执行宏任务。
宏任务队列:
微任务队列:
操作完毕后添加任务至微任务队列
微任务队列进行排序
微任务队列将排序好的任务放入放入主线程执行
{
new Promise((a, b) => {
a("OK");
b("No");
}).then(a => {
console.log("OK-OK")
}, b => {
console.log("No-No")
})
}
微任务与宏任务
js
当Promise执行到处理的时候(下方的resolve())会产生微任务。
微任务在下一次轮询时会执行。需要主线程执行完毕后执行
let promise = new Promise(resolve=>{
setTimeout(()=>{
console.log("third-running");
resolve();
},100)
console.log("first-running")
}).then(next=>{
console.log("fourth-running")
})
console.log("second-running")
微任务中的主线任务=>宏任务中的主线任务=>宏任务中的微任务=>微任务中的微任务
单一状态与状态中转
js
promise触发后状态不可逆
let pro1 = new Promise((resolve, reject) => {
setTimeout(()=>{
reject("post2");
},2000)
})
let pro2 = new Promise((resolve, reject) => {
resolve(pro1);
}).then(r => { console.log('right' + r) }, w => { console.log('wrong' + w) })
then
js
1、多个then如果未处理,会继续顺着向下找寻处理的then
2、单处理时,可设置null
let promise = new Promise((a, b) => {
b("request rejected");
}).then().then(null, reason => {
console.log(`Request error ${reason}`);
})
js
Promise返回的也是个Promise
多个then连续时,会根据上一个处理是否存在来进行处理
let p1 = new Promise((a, b) => {
// a();
b();
})
let p2 = p1.then(a => { console.log("right2") }, b => { console.log("error2") });
let p3 = p2.then(a=>{console.log("right3")},b=>{console.log("error3")});
js
返回值是成对出现的
这样也是一个promise,是内部封装的promise
.then(value=>{return {then(resolve,reject){
}
}})
其它类型promise封装
js
let promise = new Promise((resolve, reject) => {
resolve();
}).then(run => {
return class {
static then(resolve, reject) {
resolve("OK");
}
}
}, stp => { console.log("stop in 2") }).then(value => {
console.log(`${value} over`);
})
catch接收
js
new Promise((resolve,reject)=>{
resolve();
})
.then(resolve2=>{return new Promise((new_resoleve,new_reject)=>{
new_reject("new_reject err");
})},reject2=>{console.log("2 is err")})
.catch(err=>{console.log(`${err}cath error`)});
错误处理
js
new Promise((resolve, reject) => {
resolve("nope");
})
.then(value => {
if (value != "yes") {
return Promise.reject("no")//以上代码等同于throw new Error("no")
}
},null)
.catch(value => {
console.log(value + "---")
})
自定义处理
class DIY_error extends Error{
constructor(msg){
super(msg);
this.err_name = "address head error";
}
}
function request(URL){
let reg = /^https?/i;
if(!reg.test(URL)){
throw new DIY_error("address head error");
}
}
finally
js
无论陈工还是失败都会执行
用于发送完毕后关闭/结束某些功能
异步加载图片
js
function loading_img(src){
return new Promise((resolve,reject)=>{
let image = new Image();
image.src = src;
image.onload = ()=>{resolve(image)};
image.onerror = reject;
document.body.appendChild(image);
})
}
loading_img("./demo.png").then(image=>{
image.style.border = "solid 2px black"
})
定时器封装
js
function timeout(delay = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve() }, delay);
})
}
timeout(4000).then(re => {
console.log("OK")
return timeout(8000)
})
.then(a => { console.log("right") });
all接口
js
mesuare:
Promise.all([p1,p2,p3...])
criteria:
all are true is true
全部返回的promise状态必须为已解决状态
{
const first = new Promise((resolve, reject) => {
setTimeout(() => {
reject("first is ok");
}, 1000)
}).catch(()=>{
console.log("fitst is okk")
})//catch 默认返回解决状态
const second = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("second is ok")
})
})
let all_promise = [first, second];
Promise.all(all_promise).then(result => {
console.log("全部成功");
}).catch(() => {
console.log("有至少一个不成功")
})
}
allSettled
js
都收集起来。 全部收起来之后再处理。
本身返回的值为成功状态
let all_promises = [first, second];
Promise.allSettled(all_promises).then(value => {
let users = value.filter(user => {
return user.status == "fulfiled";
})
})
race
js
接收多个promise,哪个快接收哪个
谁快用哪个,以快为准
Promise队列
js
let res = Promise.resolve();
res.then(value => {
return new Promise(resolve => {
setTimeout(() => {
console.log("1")
resolve("errorL:value");
}, 1000)
})
}).then(v=>{
return new Promise(resolve=>{
setTimeout(() => {
console.log("2")
resolve("ok");
}, 1000);
})
})
上一个promise队列依赖下一个promise队列的改变
js
function queue(num) {
let promise = Promise.resolve();
num.map(v => {
promise = promise.then(_ => {
return v();
})
})
}
function p1() {
return new Promise(resolve => {
setTimeout(() => {
console.log("p1")
resolve();
}, 1000);
})
}
function p2() {
return new Promise(resolve => {
setTimeout(() => {
console.log("p2")
resolve();
}, 1000);
})
}
queue([p1,p2]);
js
function return_promise(num) {
num.reduce((promise, n) => {
return promise.then(() => {
return new Promise(resolve => {
setTimeout(() => {
console.log(n)
resolve();
}, 1000)
})
})
}, Promise.resolve())
}
return_promise([516, 516, 51, 651, 35])
async&awiat
js
async 相当于Promise
await 相当于 then
async---性质转化,如果function/class里需要先加载主进程,那么function/class需要进行async声明。
同样的,里边具体的执行代码块要用上 await方法。表示这个优先加载
class
js
class user{
constructor(name){
this.name = name;
}
then(resolve,reject){
let user = "yzh";
resolve(user);
}
}
async function usr(){
let usr1 = await new user("yang");
console.log(usr1)
}
usr()
内部封装异步
class Demo {
constructor(name) { this.name = name };
async get() {
let age = await new object();
console.log
}
}
总结
js
//普通函数生声明
function ajax(name) {
return `this is the data ${name}`
}
async function get() {
return await ajax("my");
}
get().then(v => {
console.log(v);
})
//对象调用
function ajax(name) {
return `this is the data ${name}`
}
let yzh = {
async get(name) {
return await ajax("object api");
}
}
yzh.get().then(v=>{
console.log(v)
})
//类封装
function ajax(name) {
return `this is the data ${name}`
}
class Usr {
constructor() { };
async get() {
return await ajax("this is the method by Object");
}
}
let yz = new Usr();
yz.get().then(v => {
console.log(v);
})
错误处理
js
代码不应该只考虑正常,也要考虑异常
//标准的Promise错误处理流程
async function example() {
try {
let user = await "xxx";
let lessons = await "xxx";
return Data;
} catch (args) {
alert("error report")
}
};
对于函数类型,对象类型,类类型都可以使用.catch进行捕获
await并行处理
js
function new1_promise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("new1_value");
}, 1000)
})
}
function new2_promise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("new2_value");
}, 1000)
})
}
//fn1 并行处理
async function yz() {
let h1 = new1_promise();
let h2 = new2_promise();
let h1value = await h1;
let h2value = await h2;
console.log(h1value, h2value);
setTimeout(() => {
console.log(h1, h2);
}, 2000)
}
yz()
//fn2 all处理
async function zh() {
let res = await Promise.all([new1_promise(), new2_promise()]);
console.log(res)
}
zh()