原型
异步
一、什么是单线程,和异步有什么关系
单线程:只有一个线程,同一时间只能做一件事原因:避免 DOM 渲染的冲突解决方案:异步
为什么 js 只有一个线程:避免 DOM 渲染冲突
浏览器需要渲染 DOM
JS 可以修改 DOM 结构
JS 执行的时候,浏览器 DOM 渲染会暂停
两端 JS 也不能同时执行 (都修改 DOM 就冲突了)
webworker 支持多线程,但是不能访问 DOM
解决方案存在的问题
问题一:没按照书写方式执行,可读性差
问题二:callback 中不容易模块化
二、什么是 event-loop
事件轮询,JS 实现异步的具体解决方案
同步代码,直接执行
异步函数先放在异步队列中
待同步函数执行完毕,轮询执行异步队列的函数
setTimeout(function(){
console.log(1);
},100); //100ms 之后才放入异步队列中,目前异步队列是空的
setTimeout(function(){
console.log(2); // 直接放入异步队列
})
console.log(3) // 直接执行
// 执行 3 之后,异步队列中只有 2,把 2 拿到主线程执行,2 执行完之后,异步队列中并没有任务,所以一直轮询异步队列,直到 100ms 之后 1 放入异步队列,将 1 拿到主线程中执行
$.ajax({
url:’./data.json’,
success:function(){ // 网络请求成功就把 success 放入异步队列
console.log(‘a’);
}
})
setTimeout(function(){
console.log(‘b’)
},100)
setTimeout(function(){
console.log(‘c’);
})
console.log(‘d’)
// 打印结果:
//d //d
//c //c
//a //b
//b //a
// 真实环境不会出现 dacb
三、是否用过 jQuery 的 Deferred
jQuery1.5 的变化
使用 jQuery Deferred
初步引入 Promise 概念
jQuery1.5 之前
var ajax = $.ajax({
url:’./data.json’,
success:function(){
console.log(‘success1’);
console.log(‘success2’);
console.log(‘success3’);
},
error:function(){
console.log(‘error’);
}
})
console.log(ajax); // 返回一个 XHR 对象
jQuery1.5 之后
var ajax = $.ajax(‘./data.json’);
ajax.done(function(){
console.log(‘success1’)
})
.fai(function(){
console.log(‘fail’)
})
.done(function(){
console.log(‘success2’);
})
console.log(ajax); //deferred 对象
var ajax = $.ajax(‘./data.json’);
ajax.then(function(){
console.log(‘success1’)
},function(){
console.log(‘error1’);
})
.then(function(){
console.log(‘success2’);
},function(){
console.log(‘error’);
})
// 使用
var w = waithandle()
w.then(function(){
console.log(‘ok1’);
},function(){
console.log(‘err2’);
})
.then(function(){
console.log(‘ok2’);
},function(){
console.log(‘err2’);
})
// 还有 w.wait w.fail
无法改变 JS 异步和单线程的本质
只能从写法上杜绝 callback 这种形式
它是一种语法糖,但是解耦了代码
很好的提现:开放封闭原则 (对扩展开放对修改封闭)
使用 jQuery Deferred
// 给出一段非常简单的代码,使用 setTimeout 函数
var wait = function(){
var task = function(){
console.log(‘ 执行完成 ’);
}
setTimeout(task,2000)
}
wait();
// 新增需求:要在执行完成之后进行某些特别复杂的操作,代码可能会很多,而且分好几个步骤
function waitHandle(){
var dtd = $.Deferred();// 创建一个 deferred 对象
var wait = function(dtd){// 要求传入一个 deferred 对象
var task = function(){
console.log(“ 执行完成 ”);
dtd.resolve(); // 表示异步任务已完成
//dtd.reject() // 表示异步任务失败或者出错
};
setTimeout(task,2000);
return dtd;
}
// 注意,这里已经要有返回值
return wait(dtd);
}
/*
* 总结:dtd 的 API 可分成两类,用意不同
* 第一类:dtd.resolve dtd.reject
* 第二类:dtd.then dtd.done dtd.fail
* 这两类应该分开,否则后果严重!
* 可以在上面代码中最后执行 dtd.reject() 试一下后果
*/
使用 dtd.promise()
function waitHandle(){
var dtd = $.Deferred();
var wait = function(){
var task = function(){
console.log(‘ 执行完成 ’);
dtd.resolve();
}
setTimeout(task,2000)
return dtd.promise(); // 注意这里返回的是 promise,而不是直接返回 deferred 对象
}
return wait(dtd)
}
var w = waitHandle(); //promise 对象
$.when(w).then(function(){
console.log(‘ok1’);
},function(){
console.log(‘err1’);
})
/*
只能被动监听,不能干预 promise 的成功和失败
*/
可以 jQuery1.5 对 ajax 的改变举例
说明如何简单的封装、使用 deferred
说明 promise 和 Defrred 的区别
要想深入了解它,就需要知道它的前世今生
四、Promise 的基本使用和原理
基本语法回顾
异常捕获
// 规定:then 只接受一个函数,最后统一用 catch 捕获异常
多个串联
var scr1 = ‘https://www.imooc.com/static/img/index/logo_new.png’;
var result1 = loadImg(src1);
var src2 = ‘https://www.imooc.com/static/img/index/logo_new.png’;
var result2 = loadImg(src2);
result1.then(function(img1) {
console.log(‘ 第一个图片加载完成 ’, img1.width);
return result2;
}).then(function(img2) {
console.log(‘ 第二个图片加载完成 ’, img2.width);
}).catch(function(ex) {
console.log(ex);
})
Promise.all 和 Promise.race
//Promise.all 接收一个 promise 对象的数组
// 待全部完成后,统一执行 success
Promise.all([result1, result2]).then(datas => {
// 接收到的 datas 是一个数组,依次包含了多个 promise 返回的内容
console.log(datas[0]);
console.log(datas[1]);
})
//Promise.race 接收一个包含多个 promise 对象的数组
// 只要有一个完成,就执行 success
Promise.race([result1, result2]).then(data => {
//data 即最先执行完成的 promise 的返回值
console.log(data);
})
Promise 标准
三种状态:pending,fulfilled,rejected
初始状态:pending
pending 变为 fulfilled, 或者 pending 变为 rejected
状态变化不可逆
promise 必须实现 then 这个方法 then() 必须接收两个函数作为标准 then
五、介绍一下 async/await(和 Promise 的区别、联系)
六、总结一下当前 JS 结局异步的方案
虚拟 DOM
MVVM 和 vue
组件化和 React
hybrid
未完待续,每日更新