单线程、异步、deferred与promise

1.单线程

概念:只有一个线程,同一时间只能做一件事
原因:避免DOM渲染的冲突

  • 浏览器需要渲染DOM
  • JS可以修改DOM结构
  • JS执行的时候,浏览器DOM渲染会停止
  • 两段JS也不能同时执行(都修改DOM就冲突了)
  • webworker支持多线程,但是不能访问DOM
    所以js是单线程
    解决:异步
    js异步存在的问题:
  • 没按照书写方式执行,可读性差
  • callback中不容易模块化
    实现方式:event-loop

2.event-loop

概念:事件轮询,时间循环(js实现异步的具体解决方案)
实现过程:

  • 同步代码(不在异步函数中的),直接执行
  • 异步函数先放在异步队列中
  • 待同步函数执行完毕,轮训执行

3.jQuery的deferred

//jquery 1.5之前

var ajax = $.ajax({
	url:'./data.json',
	success:function(){
		console.log('success 1');
		console.log('success 2');
	},
	error:function(){
		console.log('error');
	}
});


//jquery 1.5之后

var ajax = $.ajax('./data.json');
ajax.done(function(){
	console.log('success a');
}).fail(function(){
	console.log('fail 1');
}).done(function(){
	console.log('success b');
}).fail(function(){
	console.log('fail 2');
});

jquery 1.5之后版本与之前相比:

  • 无法改变JS异步和单线程的本质
  • 只能从写法上杜绝callback这种形势
  • 它是一种语法糖形势,但是解耦了代码
  • 很好的体现了开放封闭原则(对扩展开放,对修改封闭)

可以理解为promise是由jQuery的deferred演化而来

jQuery的deferred的使用

function waitHandle(){
	var dtd = $.Deferred(); // 定义一个deferred实例
	//对dtd进行一些操作
	var wait function(dtd){
		var task = function(){
			console.log('执行完成');

			//成功执行
			dtd.resolve();
			//失败执行
			// dtd.reject();
		}
		setTimeout(task,2000);
		//wait 返回
		return dtd;
	}
	//最终返回
	return wait(dtd);
}

//调用
var w = waitHandle();
w.then(function(){ // 成功
	console.log('ok 1');
}, function(){ // 失败
	console.log('error 1');
}).then(function(){ // 可链式操作
	console.log(ok 2);
}, function(){
	console.log('error 2');
});

//注意
// 如果前边是dtd.resolve(),将打印出ok 1,ok2
// 如果前边是dtd.reject(),后边调用的将不能再链式操作,如果需要多次,需要将w.then方法分别书写,链式操作将会打印出error 1,ok2,error 2

总结
dtd的API可以分为两类

  • 第一类:dtd.resolve dtd.reject 主动触发
  • 第二类:dtd.then dtd.done dtd.fail 被动监听
  • 这两类应该分开,不然后果很严重

**解决:**用dtd.promise()

function waitHandle(){
	var dtd = $.Deferred(); // 定义一个deferred实例
	//对dtd进行一些操作
	var wait function(dtd){
		var task = function(){
			console.log('执行完成');

			//成功执行
			dtd.resolve();
			//失败执行
			// dtd.reject();
		}
		setTimeout(task,2000);
		//wait 返回
		return dtd.promise();
	}
	//最终返回
	return wait(dtd);
}

//调用
var w = waitHandle(); //promise对象
$.when(w).then(function(){ // $.when()将w继续封装一次才能执行.then
	console.log('ok 1');
}, function(){ // 失败
	console.log('error 1');
}).then(function(){ // 可链式操作
	console.log(ok 2);
}, function(){
	console.log('error 2');
});

promise和Deferred的区别

  • Deferred有主动触发的函数(API),也有被动监听的函数(API),这两种函数混合很容易被外部篡改,通过生成一个promise对象来进行隔离,promise只能被动监听,不能主动触发修改。可以理解为promise是由deferred演变而来的

4.promise

基本语法详见上一篇 普通异步加载与promise
promise异常捕获

function loadImg(src) {
	const promise = new Promise(function(resolve,reject){
		img.onload = function(){
			resolve(img); 
		}
		img.onerror = function(){
			reject(‘图片加载失败’);
		}
		img.src = src;
	});
	return promise;
}
var src = 'http://www.baidu.com/img/bd_logo1.png';
var result = loadImg(src);

// 规定then只接受一个参数(成功的回调函数),最后统一用catch捕获异常
result.then(function(img){
	console.log(img.width);
}).then(function(img){
	console.log(img.height);
}).catch(function(ex){
	//最后统一捕获异常
	console.log(ex);
})

出现多个任务时,promise还可以串联使用

function loadImg(src) {
	const promise = new Promise(function(resolve,reject){
		img.onload = function(){
			resolve(img); 
		}
		img.onerror = function(){
			reject(‘图片加载失败’);
		}
		img.src = src;
	});
	return promise;
}

var src1 = 'http://www.baidu.com/img/bd_logo1.png';
var result1 = loadImg(src1);
var src2 = 'http://www.baidu.com/img/bd_logo2.png';
var result2 = loadImg(src2);
// 规定then只接受一个参数(成功的回调函数),最后统一用catch捕获异常
result.then(function(img1){
	console.log(‘第一个图片加载完成’);
	return result2; // 返回result2,即第二个加载任务,使接下来的.then()对象变为result2
}).then(function(img2){
	console.log(‘第二个图片加载完成’);
}).catch(function(ex){
	//最后统一捕获异常
	console.log(ex);
})

Promise.all 和 Promise.race

Promise.all 接受一个promise对象的数组,待全部完成之后,统一执行success
Promise.race 接受一个包含多个promise对象的数组,只要有一个完成,就执行success

function loadImg(src) {
	const promise = new Promise(function(resolve,reject){
		img.onload = function(){
			resolve(img); 
		}
		img.onerror = function(){
			reject(‘图片加载失败’);
		}
		img.src = src;
	});
	return promise;
}

var src1 = 'http://www.baidu.com/img/bd_logo1.png';
var result1 = loadImg(src1);
var src2 = 'http://www.baidu.com/img/bd_logo2.png';
var result2 = loadImg(src2);
// Promise.all()两个都完毕才执行
Promise.all([result1,result2],[]).then(function(datas){ // 接受datas是一个数组,依次包含了多个promise返回的内容
	console.log(‘all’,datas[0]); // 将打印出img1的img标签
	console.log(‘all’,datas[1]); // 将打印出img2的img标签
});
// Promise.race() 两个只有一个完毕就执行
Promise.race([result1,result2]).then(function(data){
	console.log('race',data);  // data即最先执行完成的promise的返回值
});

// 这里会先输出race和先加载完毕的img标签,再输出all和两个加载完毕的img标签,因为race是只有有一个完毕就会执行,所以会比all先执行完

Promise状态变化

  • 三种状态:pending fulfilled rejected
  • 初始状态是pending
  • 只能pending变为fulfilled,或者pending变为rejected
  • 状态变化不可逆

then

  • Promise实例必须实现then这个方法
  • then()必须可以接受两个函数作为参数(一个是成功是的回调函数,一个是失败时的回调函数)
  • then()返回的必须是一个Promise实例

async/await

  • then只是将callback拆分了
  • async/await是最直接的同步写法
  • 使用await,函数必须用async标识
  • await后面跟的是一个Promise实例
  • 需要安装babel-polyfill
  • 使用了Promise,并没有和Promise冲突
  • 完全是同步的写法,再也没有回调函数
  • 但是,任何写法的改变,都改变不了JS单线程、异步的本质
function loadImg(src) {
	const promise = new Promise(function(resolve,reject){
		img.onload = function(){
			resolve(img); 
		}
		img.onerror = function(){
			reject(‘图片加载失败’);
		}
		img.src = src;
	});
	return promise;
}

var src1 = 'http://www.baidu.com/img/bd_logo1.png';
var src2 = 'http://www.baidu.com/img/bd_logo2.png';

const load = async function(){
	const result1 = await loadImg(src1);
	console.log(result1); //返回img1的img标签
	const result2 = await loadImg(src2);
	console.log(result2); //返回img2的img标签
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值