JavaScript异步和单线程
例:
// 循环执行期间,JS 执行和DOM渲染暂时卡顿
var i, sum = 0;
for(var i = 0; i < 1000000000; i++) {
sum += 1;
}
console.log(sum); // alert 不处理,JS 执行和DOM渲染暂时卡顿
alert('hello');
console.log(2);
console.log(100)
setTimeout(function() {
console.log(200) //反正1000ms 之后执行
},1000) //先不管它,先让其他JS代码执行
console.log(300);
var ajax = $.ajax({
url: './data.json',
success: function(result) { //ajax加载完才执行
console.log(result); //先不管它,先让其他JS代码执行
}
})
console.log(ajax) //{readyState: 1, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
console.log(200); //




// jQuery1.5之前
var ajax = $.ajax({
url: './data.json',
success: function(result) {
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');
})
.fail(function() {
console.log('error1');
})
.done(function() {
console.log('success2')
})
console.log(ajax); //返回一个deferred对象,可以进行链式操作 // 还可以使用很像promise写法
var ajax = $.ajax('./data.json');
ajax.then(function(){
console.log('success1');
},function(){
console.log('error1');
}).then(function(){
console.log('success2');
},function(){
console.log('error2');
})
2,jQuery Deferred应用
看一个简单的例子:
// 给出一段非常简单的异步操作代码,使用setTimeout函数
var wait = function() {
var task = function() {
console.log('执行完成');
//
//
//
}
setTimeout(task, 1000)
}
wait()
// 新增需求:要在执行完成之后进行某些特别复杂的操作,代码可能会很多,而且分好几个步骤
使用Deferred:(开放封闭原则)
function waitHandler() {
// 定义
var dtd = $.Deferred(); //创建一个deferred对象
var wait = function(dtd) { //要求传入一个deferred对象
var task = function() {
console.log('执行完成');
// 成功
dtd.resolve(); //表示异步任务已经完成
// 失败
// dtd.reject(); //表示异步任务失败或出错
}
setTimeout(task, 1000)
// wait返回
return dtd; //要求返回deferred对象
}
// 最终返回 注意这里一定要有返回值
return wait(dtd);
} var w = waitHandler();
w.then(function() {
console.log('ok1');
}, function() {
console.log('err1');
}).then(function() {
console.log('ok2');
}, function() {
console.log('err2');
}) // 还有 w.done w.fail
执行reject
function waitHandler() {
// 定义
var dtd = $.Deferred(); //创建一个deferred对象
var wait = function(dtd) { //要求传入一个deferred对象
var task = function() {
console.log('执行完成');
// 成功
// dtd.resolve(); //表示异步任务已经完成
// 失败
dtd.reject(); //表示异步任务失败或出错
}
setTimeout(task, 1000)
// wait返回
return dtd; //要求返回deferred对象
}
// 最终返回 注意这里一定要有返回值
return wait(dtd);
} var w = waitHandler();
w.then(function() {
console.log('ok1');
}, function() {
console.log('err1');
})
w.then(function() { //reject需要分开,不然执行顺序就错啦
console.log('ok2');
}, function() {
console.log('err2');
})
这里注意一个原则:开放封闭原则
总结,dtd的API可分成两类,用意不同
第一类(主动执行):dtd.resolve dtd.reject
第二类(监听):dtd.then dtd.done dtd.fail
这两类应该分开,否则后果很严重
可在上面代码最后执行dtd.reject()试下结果
使用dtd.promise()
function waitHandler(){
var dtd = $.Deferred();//Deferred
var wait = function(dtd) {
var task = function(){
console.log('执行完成');
dtd.resolve();
}
setTimeout(task,2000);
return dtd.promise();//注意,这里返回的是promise,而不是直接返回deferred对象
}
return wait(dtd);
}
var w = waitHandler();//经过上面的改动,w接收的就是一个promise对象
$.when(w)
.then(function(){
console.log('ok1');
})
.then(function(){
console.log('ok1');
})
w.reject()//执行这句会报错 w.reject is not a function promise不能使用,只有监听的方法了,使用者只能监听,开发人员封装的时候才能用
说明promise和deferred区别: promise只能被动监听,不能主动执行
1,基本语法回顾(备注:现在高级浏览器基本都支持promise,如果有些不支持,可以在cdn上找,引入 bluebird )
<script src="https://cdn.bootcss.com/bluebird/3.5.1/bluebird.min.js"></script>
function loadImg(src) {
const promise = new Promise(function(resolve, reject) { //new Promise实例
var img = document.createElement('img');
img.src = src; img.onload = function() {
resolve(img);
}
img.onerror = function() {
reject('图片加载失败');
}
});
return promise; //返回 Promise实例
}
var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo.png";
var result = loadImg(src); //Promise实例
result.then(function(img) { //then监听结果,成功时执行resolve(), 失败时执行reject()
console.log(1, img.width); //1 164
return img;
}, function(img) {
console.log('failed');
return img;
}).then(function(img) {
console.log(2, img.height) //2 36
})
2,异常捕获
// 规定:then只接受一个参数(成功的处理函数),最后统一用catch捕获异常
// var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo.png";
var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo_1.png";//写一个不存在的地址
var result = loadImg(src);
result.then(function(img) {
console.log(img.width);
return img;
}).then(function(img) {
console.log(img.height);
}).catch(function(ex) {
// 最后统一用catch捕获异常
console.log(ex); //图片加载失败 (logo_1.png:1 GET https://shared-https.ydstatic.com/dict/v2016/result/logo_1.png 404 (Not Found))
})
自定义错误:
function loadImg(src) {
const promise = new Promise(function(resolve, reject) { //new Promise实例
var img = document.createElement('img');
// 模拟抛出错误 模拟语法错误,逻辑之外的bug
throw new Error('自定义错误');
img.src = src; img.onload = function() {
resolve(img);
}
img.onerror = function() {
reject('图片加载失败');
}
});
return promise; //返回 Promise实例
} // 规定:then只接受一个参数(成功的处理函数),最后统一用catch捕获异常
var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo.png";
// var src = "https://shared-https.ydstatic.com/dict/v2016/result/logo_1.png"; //写一个不存在的地址
var result = loadImg(src);
result.then(function(img) {
console.log(img.width);
return img;
}).then(function(img) {
console.log(img.height);
}).catch(function(ex) {
// 最后统一用catch捕获异常
console.log(ex);
})
3,多个串联
// 多个串联 图片只是用来模拟,实际可能更多的不是用图片,比如处理用户信息啥的,加载用户信息的时候,先拿到用户信息,再去处理其他信息等
var src1 = 'https://shared-https.ydstatic.com/dict/v2016/result/logo.png';
var result1 = loadImg(src1);
var src2 = 'https://img.mukewang.com/user/57b98e990001351004400440-100-100.jpg';
var result2 = loadImg(src2); // 链式操作
result1.then(function(img1) {
console.log('第一个图片加载完成', img1.width);
return result2; //重要!!!
}).then(function(img2) {
console.log('第二个图片加载完成', img2.width);
}).catch(function(ex) {
// 最后统一用catch捕获异常
console.log(ex);
})
4,Promise.all (全部promise实例完成后) 和 Promise.race (只要有一个promise实例完成)
// Promise.all 接收一个包含多个promise实例的数组,待全部完成之后,统一执行success
var src1 = 'https://shared-https.ydstatic.com/dict/v2016/result/logo.png';
var result1 = loadImg(src1); //pending
var src2 = 'https://img.mukewang.com/user/57b98e990001351004400440-100-100.jpg';
var result2 = loadImg(src2);
Promise.all([result1, result2]).then(datas => {
// 接收到的datas是一个数组,依次包含了多个promise返回的内容
console.log('all', datas[0]); //all <img src="https://shared-https.ydstatic.com/dict/v2016/result/logo.png">
console.log('all', datas[1]); //all <img src="https://img.mukewang.com/user/57b98e990001351004400440-100-100.jpg">
})
Promise.race (只要有一个promise实例完成)
// Promise.race 接收一个包含多个promise实例的数组
// 只要有一个完成,就执行success
Promise.race([result1, result2]).then(data => {
// data即最先执行完成的promise的返回值
console.log('race', data); //race <img src="https://shared-https.ydstatic.com/dict/v2016/result/logo.png">
})
promise标准
1,关于“标准”的闲谈
任何技术推广使用都需要一套标准来支撑
如html css js等,无规矩不成方圆
任何不符合标准的东西,终将会被用户抛弃
不要挑战标准,不要自造标准
2,状态变化
三种状态:pending fulfilled rejected
pending: 初始状态
fulfilled: 成功
rejected:失败
pending到fulfilled,或者pending到rejected,状态不可逆
3,then
Promise实例必须实现then方法
then()必须可以接收两个函数作为参数
then()返回的必须是一个Promise实例
如果then中没有返回promise实例,则默认返回的是上一个promise实例,如果返回了一个promise实例,那就默认为返回的promise实例
1,then只是将callback拆分了
// then只是将callback拆分了
var w = waitHandler();
w.then(function() {
console.log('ok1');
}, function() {
console.log('err1');
}).then(function() {
console.log('ok2');
}, function() {
console.log('err2');
})
2,async/await是最直接的同步写法
// async/await是最直接的同步写法
const load = async function() {
const result1 = await loadImg(src1);
console.log(result1);
const result2 = await loadImg(src2);
console.log(result2);
}
load()
完整的:
import 'babel-polyfill'; //引入babel-polyfill // async/await是最直接的同步写法
function loadImg(src) {
const promise = new Promise(function(resolve, reject) {
var img = document.createElement('img');
img.src = src; img.onload = function() {
resolve(img);
}
img.onerror = function() {
reject('图片加载失败');
}
});
return promise;
}
var src1 = 'https://shared-https.ydstatic.com/dict/v2016/result/logo.png';
var src2 = 'https://img.mukewang.com/user/57b98e990001351004400440-100-100.jpg';
// async/await是最直接的同步写法
const load = async function() { //函数必须用async标识
const result1 = await loadImg(src1); //await后面跟的是一个Promise实例
console.log(result1);
const result2 = await loadImg(src2); //await后面跟的是一个Promise实例
console.log(result2);
}
load()
用法:
要在函数体内使用await,函数必须用async标识
await后面跟的是一个Promise实例
需要安装babel-polyfill
npm i --save-dev babel-polyfill
3,总结
使用了Promise,并没有和Promise冲突
完全是同步的写法,再也没有回调函数
但是:改变不了js单线程,异步的本质
1,jquery Deferred
2,Promise
3,Async/await
JavaScript异步和单线程的更多相关文章
- 【前端知识体系-JS相关】深入理解JavaScript异步和单线程
1. 为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Jav ...
- JavaScript 异步和单线程
JavaScript语言本身是单线程的,所以它自身不可能是异步.所谓单线程,就必然意味着:所有任务需要排队,前一个任务结束,才会执行后一个任务. 但js的宿主环境(比如浏览器,Node)是多线程的.宿 ...
- JavaScript异步编程的主要解决方案—对不起,我和你不在同一个频率上
众所周知(这也忒夸张了吧?),Javascript通过事件驱动机制,在单线程模型下,以异步的形式来实现非阻塞的IO操作.这种模式使得JavaScript在处理事务时非常高效,但这带来了很多问题,比如异 ...
- JavaScript异步编程原理
众所周知,JavaScript 的执行环境是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,这就和火车站洗手间门口的等待一样,前面的那个人没有搞定,你就只能站在后面排队等着. ...
- javascript异步编程的前世今生,从onclick到await/async
javascript与异步编程 为了避免资源管理等复杂性的问题, javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为 ...
- JavaScript到底是不是单线程
JavaScript到底是不是单线程 JavaScript引擎 在了解计时器内部运作前,我们必须清楚一点,触发和执行并不是同一概念,计时器的回调函数一定会在指定delay的时间后被触发,但并不一定立即 ...
- Javascript定时器(一)——单线程
一.JavaScript 引擎是单线程的 可以从下面的代码中看到,第一个用setTimeout中的代码是死循环,由于是单线程,下面的两个定时器就没机会执行了. <script type=&quo ...
- JavaScript异步机制
单线程异步执行的JavaScript JavaScript是单线程异步执行的,单线程意味着代码在任务队列中会按照顺序一个接一个的执行.异步代表JavaScript代码在任务队列中的顺序并不完全等同于代 ...
- 5分种让你了解javascript异步编程的前世今生,从onclick到await/async
javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是 ...
随机推荐
- Swift5 语言指南(十二) 属性
属性将值与特定类,结构或枚举相关联.存储的属性将常量和变量值存储为实例的一部分,而计算属性则计算(而不是存储)值.计算属性由类,结构和枚举提供.存储的属性仅由类和结构提供. 存储和计算属性通常与特定类 ...
- Appium发送中文或其他语言的问题
1. 需要在配置信息中增加'unicodeKeyboard' = “True”字段,如下: def driver_weixin(platformVersion="6.0.1",de ...
- [视频]K8飞刀--WinRAR远程代码执行漏洞利用视频
[视频]K8飞刀--WinRAR远程代码执行漏洞利用视频 链接:https://pan.baidu.com/s/17_0kgNsDejJS0hvgLiMD7A 提取码:zkc2
- 在Vue中使用CodeMirror 格式显示错误 行数错乱 & 代码隐藏
项目需要在线展示和编辑Json文件,所以需要找一个代码编辑器,因为我们的项目直接使用的 vueAdmin-template 这个模板 json编辑器也是直接从 vue-element-admin 项目 ...
- RobotFramework测试问题二:各种元素不能定位问题
各种元素不能定位问题 一.元素定位 A. Click Element + xpath B. Click Element + contains C. Execute Javascript + getEl ...
- ElasticSearch实战-编码实践
1.概述 前面在<ElasticSearch实战-入门>中给大家分享如何搭建这样一个集群,在完成集群的搭建后,今天给大家分享如何实现对应的业务功能模块,下面是今天的分享内容,目录如下所示: ...
- cgroup其他部分 IO + hugepage
cgroup还有其他一些限制特性,如io,pid,hugetlb等,这些用处不多,参见Cgroupv1.下面介绍下与系统性能相关的io和hugepage,cgroup的io介绍参考Cgroup - L ...
- Spring Boot + Spring Cloud 构建微服务系统(九):配置中心(Spring Cloud Config)
技术背景 如今微服务架构盛行,在分布式系统中,项目日益庞大,子项目日益增多,每个项目都散落着各种配置文件,且随着服务的增加而不断增多.此时,往往某一个基础服务信息变更,都会导致一系列服务的更新和重启, ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十四):项目打包部署
项目打包部署 安装MySQL镜像 注意:如果使用docker镜像安装MySQL,也需要在前端部署主机安装MySQL,因为备份还原功能是使用MySQL的本地命令进行操作的. 下载镜像 执行以下命令,拉取 ...
- apache tomcat搭建负载均衡(实现集群中的session同步)
原理:tomcat 做个WEB服务器有它的局限性,处理能力低,效率低.承受并发小(1000左右).但目前有不少网站或者页面是JSP的.并采用了tomcat做为WEB,因此只能在此基础上调优. 目前采取 ...