同步和异步问题

一、什么叫同步、异步:
1、同步:同步操作没有结束之前,后面的代码是无法执行的。
2、异步:异步操作没有结束之前,后面的代码是可以执行的。
二、哪些是异步问题:
1、计时函数:setTimeout()、setInterval()。
2、资源加载(I/O操作):在JavaScript脚本代码中动态加载资源。
3、XHR请求:利用Ajax技术向服务器发出请求。
三、异步问题的实际案例:
1、计时函数产生的异步问题:

function f1(){
  console.log("第一个");
}
function f2(){
  setTimeout(function(){
    console.log("第二个");
  },0);     //时间为0,整个操作也是异步的
}
function f3(){
  console.log("第三个");
}
f1();
f2();
f3();

(1)ES4/ES5解决方案:使用回调函数解决。
将异步操作的内容进行改造,设置一个回调函数作为参数保证同步性。

 function f1(){ console.log(F1); }
     function f2(callback){     //函数作为形参
       window.setTimeouut(function(){
         console.log(F2);
         callback();
},2000);
}
     function f3(){ console.log(F3); }
     //执行上述函数并保证F1 F2 F3的时序性
     f1();
     f2(f3);   //将函数名f3传递给形参callback,callback成为了函数f3的一个引用

(2)回调函数作为参数:
 可以是一个已经定义好的函数名。
 可以是一个当时定义的匿名函数。

  f1();
      f2(function(){
        //可以书写想与f2函数的执行内容同步的任意代码
        var m=100,n=1000;
        console.log(m+n);
})
      实际应用:jQuery中有一个方法 animate({},duration,callback)
      $(“#ball”).animate({
        “margin-left”:+=200px”
},2000,function(){
  // 当动画结束之后执行该函数内部的代码
})

(3)当有两个异步操作时如何通过回调函数处理:

function f1(){
	console.log("第一个");
}
function f2(callback,callback2){
	window.setTimeout(function(){
		console.log("第二个");
		callback(callback2);
	},2000)
}
function f3(callback){
	window.setTimeout(function(){
		console.log("第三个");
		callback();
	},5000)	
}
function f4(){
	console.log("第四个");
}
f1()
f2(f3,f4)

** 结论:回调函数容易造成“回调地狱”。**
2、资源加载的异步问题:

 // var imgNode = document.createElement("img");
var img=new Image();
img.src="images/06.jpg";
pic.appendChild(img);

console.log(img.width);    //0
console.log(img.height);   //0

解决方案:可以将输出涉及到资源的代码书写在资源的onload事件中,若资源加载失败,
可以将加载失败后执行的代码书写在资源的onerror事件中。
例:利用回调函数将加载图片的代码进行封装。

 function loadImage(parent,url,success,failure){
	  var img=new Image();
	  img.src=url;
	  parent.appendChild(img);
img.onload=function(){
		success();
	  }
img.onerror=function(){
		failure();
	  }
}

loadImage(box,"images/12.jpg",function(){
	console.log("图片加载成功了");
},function(){
	console.log("图片加载失败了");
})

3、结论:回调函数可以解决异步问题。
四、ES6引入了Promise对象解决异步问题:
1、语法格式:

let promise = new Promise(function(resolve,reject){
    //书写异步操作的代码
    if(异步操作执行成功){
       resolve();
}
if(异步操作执行失败){
   reject();
}
})

promise.then(function(){
   //书写调用了resolve()时执行的代码
},function(){
   //书写调用了reject()时执行的代码
})

2、例1:加载一张图片,在图片加载成功后输出图片的宽度和高度,若图片加载失败则显示
加载失败的文本提示。

let promise=new Promise(function(resolve,reject){
	var img=new Image();
	img.src="images/2.jpg";
	box.appendChild(img);
	img.onload=function(){
		resolve(this);
	}
	img.onerror=function(){
		reject();
	}
})

promise.then(function(obj){
	console.log(`图片宽度=${obj.width}`);
	console.log(`图片高度=${obj.height}`);
},function(){
	console.log("图片加载失败");
})
 3、例2:利用Promise封装加载一张图片的功能。
function loadImage(parent,url){
	return new Promise((resolve,reject)=>{
		var img=new Image();
		img.src=url;
		parent.appendChild(img);
		img.onload=function(){
			resolve(this);
		}
		img.onerror=function(){
			reject();
		}
	})
}

loadImage(box,'images/3.jpg').then(function(obj){
	console.log("图片加载成功");
	console.log(obj.width);
}).catch(function(){
	console.log("图片加载失败");
})

** 4、例3:封装confirm()。**

function $confirm(message){
	return new Promise((resolve,reject)=>{
		let temp=window.confirm(message);
		if(temp){
			resolve();
		}else{
			reject();
		}
	});
}

$confirm("您确定关闭吗?").then(()=>{
	console.log("关闭了");
}).catch(()=>{
	console.log("取消了");
})

5、Promise技术解决异步问题的优势:
(1)可以有多个then()连缀书写。
(2)Promise技术避免了回调地域。
(3)不仅给出了异步操作成功的代码解决方案,还给出了异步操作失败和完成的解决
方案。

new Promise(function(resolve,reject){
  //异步操作
}).then(function(){
  //异步操作成功
}).catch(function(){
  //异步操作失败
}).finally(function(){
  //异步操作完成
})

6、例4:加载多个图片。

  • 当所有图片都加载成功后,输出“所有图片加载成功”;有任意图片没有加载成功,输 出“有图片没有加载成功”。
  • 静态方法:Promise.all(array)
  • 功能:返回一个Promise实例,参数array是一个元素为Promise实例的数组。当数组中所有的Promise实例均执行resolve()方法后,整个Promise实例才会表示成功。
  • 静态方法:Promise.race(array)
  • 功能:与Promise.all()相反。
let imgs=['1.jpg','2.jpg','30.jpg','4.jpg'];
let pro=[];
for(let i=0;i<imgs.length;i++){
	let temp = loadImage(box,'images/' + imgs[i]);
	pro.push(temp);
}

Promise.all(pro).then(()=>{
	console.log("所有图片都加载成功了");
}).catch(()=>{
	console.log("有图片没有加载成功");
})

** 7、封装Ajax技术:**
(1)原生JavaScript:XMLHttpRequest()
(2)jQuery:$.ajax()
(3)Vue.js:axios
(4)小程序:wx.request()
如何利用Axios技术提交一个Ajax请求:

 	$axios.get(url,{}).then().catch();
    $axios.post(url,{}).then().catch();

**问题:**因为$axios后面还要跟具体的不同而两个方法(get()、post()),所以不能使
用function进行封装。
解决:使用类封装(混合模式:属性定义在构造函数中,方法定义在原型下)。

 // 先创建构造函数
function Axios(){}

// 创建Axios类的方法
Axios.prototype.get=function(){
}
Axios.prototype.post=function(){
}

// 创建Axios类的实例
let $axios = new Axios();

$axios.get();      //发送get请求
$axios.post();     //发送post请求

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

裴嘉靖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值