- 什么是单线程,和异步有什么关系
- 单线程——同一时间只能做一件事情
- 使用单线程原因——浏览器需要渲染dom,js可以修改dom结构,js执行时浏览器dom渲染会停止,两段js不能同时执行,为避免dom渲染冲突js只能单线程并且与浏览器渲染在同一个线程中。webworker支持多线程但不能访问dom
- 解决方案——异步
- 什么是eventloop——事件轮询,js实现异步的具体解决方案
- 同步代码,直接执行
- 异步函数先放在异步队列中
- 待同步函数执行完毕,轮询执行异步队列中的函数
- 何时被放入异步队列(实际过程中,根据ajax、计时器等的具体时间决定谁优先执行)
- 立即被放入
- 指定时间后放入
- ajax加载完成后放入
setTimeout(function(){
console.log(200)
},1000);
setTimeout(function(){
console.log(100)
});
console.log(300);
//主进程
//console.log(300)
//异步队列
//立刻被放入
function(){
console.log(100)
}
/1s后被放入
function(){
console.log(200)
}
$.ajax({
type : 'get',
datatype:'json',
url : 'data.json',
success: function(result){
console.log("a")
},
error: function(){
console.log("failed")}
})
setTimeout(function(){
console.log(200)
},10000);
setTimeout(function(){
console.log(100)
});
console.log(300);
console.log(400);
主线程
console.log(300);
console.log(400);
异步队列
立即放入
function(){
console.log(100)
}
///监听……///
ajax获取到本地json,速度很快
function(result){
console.log("a")
///监听……///
10000ms后被放入
function(){
console.log(200)
}
- jquery的Deferred
简单封装
function waitHandle() {
var dtd=$.Deferred()//创建一个deffered对象
var wait=function(dtd){//要求传入一个deffered对象
var task=function(){
console.log("ok");
dtd.resolve();//异步执行成功
dtd.reject();//异步执行失败
}
setTimeout(task,2000);
return dtd;//返回deffered对象
}
return wait(dtd);//这里一定要有返回值
}
var w=new waitHandle();
w.then(function(){
console.log('success1');
},function(){
console.log('error');
})
jquery1.5的变化:
- 无法改变js异步和单线程的本质
- 只能在写法上杜绝callback这种形式
- 是语法糖,但是解藕了代码
- 很好的体现:开放封闭原则(对扩展开放,对修改封闭)
jquery1.5之前/
var ajax=$.ajax({
url: "data.json",
success:function(){
console.log("success1");
console.log('success2')
},
error: function(){
console.log('error')
}
})
console.log(ajax)//返回一个XHR对象
jquery1.5之后分为两类/
//第一类.done .fail//
var ajax=$.ajax("data.json")
ajax.done(function(){
console.log("success1");
})
.fail(function(){
console.log('error')
})
.done(function () {
console.log('success2')
})
console.log(ajax)//返回一个Deffered对象
//第二类.then//
/与promise写法相似//
var ajax=$.ajax('data.json');
ajax.then(function(){
console.log('success1')
},function(){console.log('fail1')})
.then(function(){console.log('success 2'),
function () {console.log('fail2') }})
promise和deffered区别
function waitHandle() {
var dtd=$.Deferred()//创建一个deffered对象
var wait=function(dtd){//要求传入一个deffered对象
var task=function(){
console.log("ok");
dtd.resolve();//异步执行成功
dtd.reject();//异步执行失败
}
setTimeout(task,2000);
return dtd.promise();//返回promise对象
}
return wait(dtd);//这里一定要有返回值
}
var w=new waitHandle();
// w.reject();报错,使用者不能干扰promise的成功还是失败
w.then(function(){
console.log('success1');
},function(){
console.log('error');
})
两大类:第一类:.reject .resolve
第二类:.done .fail .then
两类不能混用
使用者不能干扰promise的成功还是失败
- Promise的基本使用和原理
- Promise状态变化
- 三种状态:pending,fulfilled,rejected
- 初始状态是pending,pending转变为fulfilled,pending转变为rejected,状态不可逆
- Promise实例必须实现then的方法,then()必须接收两个函数作为参数,then()必须返回一个Promise实例
- 如果then()中函数没有明文返回一个Promise实例,那么返回的就是调用这个.then()本身的Promise实例;如果then()中函数明文返回一个不同的Promise实例,那么后面再执行.then()时返回的就是这个新的Promise()实例
function Img(src){
const promise=new Promise(function (resolve,reject) {
var img=document.createElement('img');
img.src=src;
img.onload=function(){
console.log('ok');
resolve(img);
}
img.onerror=function(){
reject();
}
})
return promise;
}
var src="https://www.imooc.com/static/img/index/logo.png";
var result=Img(src);
result.then(function (img)
{
console.log(img.height);
return img;
},
function(){
console.log('fail');
})
异常捕获
function Img(src){
const promise=new Promise(function (resolve,reject) {
var img=document.createElement('img');
img.src=src;
img.onload=function(){
console.log('ok');
resolve(img);
}
img.onerror=function(){
reject("失败");
}
})
return promise;
}
var src=" ";//不添加图片路径
var result=Img(src);
result.then(function (img)
{
console.log(img.height);
return img;
}).catch(function(ex){//onerror事件或其他异常都通过异常捕获.catch来监听,在.then中只添加加载完成的onload事件
console.log(ex);
})
多个串联
function Img(src){
const promise=new Promise(function (resolve,reject) {
var img=document.createElement('img');
img.src=src;
img.onload=function(){
console.log('ok');
resolve(img);
}
img.onerror=function(){
reject("失败");
}
})
return promise;
}
var src1="https://www.imooc.com/static/img/index/logo.png";
var src2="https://www.imooc.com/static/img/common/appload.png";
var result1=Img(src1);
var result2=Img(src2);
result1.then(function (img1){
console.log("第一个图片加载完成",img1.width);
return result2;//如果then()中函数没有明文返回一个Promise实例,那么返回的
//就是调用这个.then()本身的Promise实例;如果then()中函数明
//文返回一个不同的Promise实例,那么后面再执行.then()时返回
//的就是这个新的Promise()实例
}).then(function (img2) {//此时.then()相当于result2.then()
console.log("第二个图片加载完成",img2.width)
}).catch(function(ex){
console.log(ex);
})
Promise.all&Promise.race
Promise.all执行数组内的所有promise对象,Promise.race只执行数组内优先加载完成的第一个promise对象
function Img(src){
const promise=new Promise(function (resolve,reject) {
var img=document.createElement('img');
img.src=src;
img.onload=function(){
console.log('ok');
resolve(img);
}
img.onerror=function(){
reject("失败");
}
})
return promise;
}
var src1="https://www.imooc.com/static/img/index/logo.png";
var src2="https://www.imooc.com/static/img/common/appload.png";
var result1=Img(src1);
var result2=Img(src2);
Promise.all([result1,result2]).then(function(datas){
console.log(datas[0])
console.log(datas[1])
})
Promise.race([result1,result2]).then(function(data){
console.log(data)
})
- async/await(和promise的区别、联系)
then只是将callback代码拆分了,async/await用同步写法实现异步操作
使用await,函数必须用async标识,await后面跟的是一个Promise实例,需要babel-polyfill
使用了Promise并没有和Promise冲突,完全是同步的写法,再也没有回调函数,改变不了js单线程、异步的本质
function Img(src){
const promise=new Promise(function (resolve,reject) {
var img=document.createElement('img');
img.src=src;
img.onload=function(){
console.log('ok');
resolve(img);
}
img.onerror=function(){
reject("失败");
}
})
return promise;
}
var src1="https://www.imooc.com/static/img/index/logo.png";
var src2="https://www.imooc.com/static/img/common/appload.png";
const load=async function(){
const result1=await Img(src1);
console.log(result1);
const result2=await Img(src2);
console.log(result1);
}
load();