异步相关
一:同步异步
XmlHttpRequest:
let url = 'static/a.json';
let xmlHttpRequest;
if(window.XMLHttpRequest){
xmlHttpRequest = new XMLHttpRequest();
}else{//兼容旧版本
xmlHttpRequest = new ActiveXObject('Microsoft.XMLHTTP')
}
xmlHttpRequest.open('GET',url,true);
xmlHttpRequest.send();
xmlHttpRequest.onreadystatechange = function() {
if(xmlHttpRequest.readyState === 4 && xmlHttpRequest.status === 200){
let obj = JSON.parse(xmlHttpRequest.responseText);
console.log(obj);
}
}
//{a: '我是A'}
Ajax原理:
//ajax的简单封装
let a = 'static/a.json';
function ajax(url,method,callback) {
let xmlHttpRequest;
if (window.XMLHttpRequest) {
xmlHttpRequest = new XMLHttpRequest();
} else {//兼容旧版本
xmlHttpRequest = new ActiveXObject('Microsoft.XMLHTTP')
}
xmlHttpRequest.open(method, url, true);
xmlHttpRequest.send();
xmlHttpRequest.onreadystatechange = function () {
if (xmlHttpRequest.readyState === 4 && xmlHttpRequest.status === 200) {
let obj = JSON.parse(xmlHttpRequest.responseText);
callback(obj)
}
}
}
ajax(a,'GET',res=>{
console.log(res);//{a: '我是A'}
})
a->b->c
地狱回调问题:
ajax(a, 'GET', res => {
console.log("aaa---", res);
ajax(b, 'GET', res => {
console.log("bbb---", res);
ajax(c, 'GET', res => {
console.log("ccc---", res);
})
})
})
aaa--- {a: '我是A'}
bbb--- {b: '我是B'}
ccc--- {c: '我是C'}
Promise解决回调地狱:
//基于上面的ajax的封装,我们进一步通过promise解决回调问题
//获取promise
function getPromise(url,method){
return new Promise((resolve,reject)=>{
ajax(url,method,res=>{
resolve(res)
})
})
}
getPromise(a,"GET").then(res=>{
console.log(res);
return getPromise(b,'GET');
}).then(res => {
console.log(res);
return getPromise(c,'GET');
}).then(res=>{
console.log(res);
})
案例:promise加载图片
const url = 'https://m.360buyimg.com/babel/jfs/t1/145983/4/5065/136336/5f313fcfEa5213607/170f4951fa1a845e.jpg.webp'
const url2 = 'https://img12.360buyimg.com/pop/s590x470_jfs/t1/136750/17/3835/71376/5f0434ecE1e5daa8d/7ab8f3deb1f8dd62.jpg.webp'
const wrapper = document.querySelector('#wrapper')
function loadImage(imgUrl) {
let p = new Promise((resolve, reject) => {
//let img = document.createElement("img");
let img = new Image();
img.onload = () => resolve(img);
img.onerror = () => {
let error = new Error("加载失败")
reject(error);
};
img.src = imgUrl;
img.height = 200
img.width = 200
})
return p;
}
loadImage(url).then(res=>{
wrapper.appendChild(res)
return loadImage(url2);
}).then(res=>{
wrapper.appendChild(res)
}).catch(err=>{
console.log(err.error,message);
})
效果:
Promise的静态方法
①Promise.resolve
②Promise.reject
③Promise.all
④Promise.race
Promise.all():Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
//上传图片
let imgArr = ['https://m.360buyimg.com/babel/jfs/t1/145983/4/5065/136336/5f313fcfEa5213607/170f4951fa1a845e.jpg.webp', 'https://img12.360buyimg.com/pop/s590x470_jfs/t1/136750/17/3835/71376/5f0434ecE1e5daa8d/7ab8f3deb1f8dd62.jpg.webp'];
let pushArr = [];
imgArr.forEach(item => {
pushArr.push(new Promise((resolve, reject) => {
resolve(item)//模拟上传后端
}))
})
Promise.all(pushArr).then(result=>{
console.log(result);
console.log('图上上传成功');
})
效果:
Promise.all().png
Promise.race():顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
let url = 'https://m.360buyimg.com/babel/jfs/t1/145983/4/5065/136336/5f313fcfEa5213607/170f4951fa1a845e.jpg.webp'
function loadImg() {
let p1 = new Promise((resolve, reject) => {
let img = new Image();
img.onload = function() {
resolve('图片加载成功')
}
img.src = url;
})
return p1
}
function delay() {
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('图片加载失败')
}, 2000)
})
return p2
}
Promise.race([loadImg(), delay()]).then(result => {
console.log(result);
})
Generator函数:
概念
Generator 函数是 ES6 提供的一种异步编程解决方案。它既是一个生成器,也是一个状态机,内部拥有值及相关的状态,生成器返回一个迭代器 Iterator 对象,我们可以通过这个迭代器,手动地遍历相关的值、状态,保证正确的执行顺序。
特征
function 关键字与函数名之间有一个星号(ES6 没有规定,function 关键字与函数名之间的星号,写在哪个位置)
函数体内部使用 yield 表达式,定义不同的内部状态
调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)
function* sum(a) {
let x = yield 1 + a;//6
let y = yield 2 + x;//8
return x + y;//16
}
//next()中参数会作为上一个yield表达式的返回值
let sum1 = sum(5);
console.log(sum1.next());//{value: 6, done: false}
console.log(sum1.next(6));//{value: 8, done: false}
console.log(sum1.next(10));//{value: 16, done: done}
yield 表达式和 next() 方法
由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield 表达式就是暂停标志。
遍历器对象的next方法的运行逻辑:
遇到 yield 表达式,就暂停执行后面的操作,并将紧跟在 yield 后面的那个表达式的值,作为返回的对象的 value 属性值
下一次调用 next() 方法时,再继续往下执行,直到遇到下一个 yield 表达式.
如果没有再遇到新的 yield 表达式,就一直运行到函数结束,直到 return 语句为止,并将 return 语句后面的表达式的值,作为返回的对象的 value 属性值.
如果该函数没有 return 语句,则返回的对象的 value 属性值为 undefined
注意:
yield 表达式后面的表达式,只有当调用next()方法、内部指针指向该语句时才会执行.
yield 语句只能用于 function* 的作用域,如果 function* 的内部还定义了其他的普通函数,则函数内部不允许使用 yield 语句.
yield 语句如果参与运算,必须用括号括起来.
next() 方法的参数:
yield 表达式本身没有返回值,或者说总是返回undefined
next() 方法可以带一个参数,该参数会改变上一个yield表达式的返回值
Iterator:
//模拟iterator的过程
function makeIterator(arr) {
let nextIndex = 0;
return {
next() {
return nextIndex < arr.length ? {value:arr[nextIndex++],done:false} : {value:undefined,done:true}
}
}
}
let it = makeIterator([1,2,3])
console.log(it.next());//{value: 1, done: false}
console.log(it.next());//{value: 2, done: false}
console.log(it.next());//{value: 3, done: false}
console.log(it.next());//{value: undefined, done: true}
原生具有iterator接口的数据结构
原生具有iterator接口的数据结构.png
对象使用for...of
let obj = {
0:"我是0",
1:"我是1",
2:"我是2",
length:3,
//添加[Symbol.iterator]方法
[Symbol.iterator] : function() {
let _this = this;
let index = 0;
return {
next:() => {
let value = _this[index];
let done = (index >= _this.length);
index++;
return {value,done}
}
}
}
};
//咱们来for...of一下
for(let v of obj){
console.log(v);
}
//结果:"我是0"
// "我是1"
// "我是2"
Module:
AMD,CMD,CommonJS,ES6的区别