问题
- 什么是单线程,和异步什么关系
- 什么是event-loop
- 是否用过jquery中的deferred
- Promise的基本使用和原理
- 介绍async/await(和Promise的联系和区别)――不是取代,而是补充
- 介绍一下异步解决方案
单线程和异步
单线程,同一时间只能做一件事,可以避免DOM渲染冲突。
- 浏览器需要渲染DOM,JS可以修改DOM结构,所以JS执行的时候,浏览器DOM渲染会暂停,且两端JS也不能同时执行。
- 虽然webworker支持多线程,但是不能访问DOM。
解决方案是异步。但异步存在问题。
- 不按照书写方式执行,可读性差
- 回调函数不容易模块化。
事件循环
同步代码,直接执行。异步函数完成先放在异步队列中。待同步函数执行完毕,轮询执行异步队列的函数。
jQuery的Deferred
-
jquery1.5的变化
var ajax = $.ajax({ url: 'data.json', success: function() { console.log('success1'); console.log('success2'); }, error: function() { console.log('error'); } })
var ajax = $.ajax('data.json'); ajax.done(function() { console.log('success1'); }) .fail(function() { console.log('error'); }) .done(function() { console.log('success1'); }) .fail(function() { console.log('error'); }) //或者下面的写法 //很像Promise写法 var ajax = $.ajax('data.json') ajax.then(function() { console.log('success1'); }, function() { console.log('error1'); }) .then(function() { cosole.log('sucess2'); }, function() { console.log('error2'); }) console.log(ajax); //返回一个XHR对象
但需要注意:
- 无法改变异步和单线程的本质
- 只能从写法上杜绝callback的形式
- 是一种语法糖,但是解耦了代码
- 很好的体现了开放封闭原则:对扩展开放,对修改封闭。
-
使用jquery Deferred。
原来函数:
var wait = function() { var task = function () { console.log('执行操作'); }; setTimeout(task, 2000); } wait();
使用deferred:
function waitHandle() { var dtd = $.Deferred(); //创建一个dtd对象 var wait = function() { var task = function (dtd) { console.log('执行操作'); dtd.resolve(); //表示异步任务完成 //dtd.reject() //表示异步任务失败 } setTimeout(task, 2000); return dtd; //返回的是dtd } return wait(dtd); //dtd进行了一部分操作,又返回出去 } var w = waitHandle(); w.then(function() { console.log('ok1'); },function() { console.log('error1'); }).then(function() { console.log('ok2'); },function(){ console.log('error2'); })
-
dtd的API有两类,用意不同:
第一类,
dtd.resolve()
、dtd.reject()
――主动执行的函数第二类,
dtd.then
:dtd.done
、dtd.fail
――被动监听的函数这两类应该分开,否则后果很严重。
-
-
初步引入Promise概念
function waitHandle() { var dtd = $.Deferred(); var wait = function() { var task = function (dtd) { console.log('执行操作'); dtd.resolve(); //表示异步任务完成 //dtd.reject() //表示异步任务失败 } setTimeout(task, 2000); return dtd.promise(); //返回的是dtd } return wait(dtd); //返回的是promise对象。 }
promise过滤掉了resolve和reject函数。只能调用监听的方法。所以外部的只能监听成功失败,而不能自己决定成功或者失败。
- 可以从jquery1.5对ajax的改变举例
- 说明如何简单的封装,使用deferred,提到开放封闭原则
- 说明promise和deferred的区别
Promise的基本使用和原理
-
基本语法
function loadImg (src) { var promise = new Promise(function(resolve, reject) { var img = document.createElement('img'); img.onload = function() { resolve(img) } img.onerror = function () { reject() } }); return promise; } var src = 'https://tse1-mm.cn.bing.net/th?id=OET.21b8717f0e7047bfa6d8e6fc10d91692&w=135&h=272&c=7&rs=1&o=5&pid=1.9'; var result = loadImg(src); result.then(function(img) { console.log(1, img.width); return img; }, function () { console.log('e1'); }).then(function (img) { console.log('2', img.width); })
-
异常捕获(reject和error)
function loadImg (src) { var promise = new Promise(function(resolve, reject) { var img = document.createElement('img'); img.onload = function() { resolve(img) } img.onerror = function () { reject() } }); return promise; } var src = ''; var result = loadImg(src); result.then(function(img) { console.log(1, img.width); return img; }, function () { console.log('e1'); }).catch(function) { console.log('图片加载失败') }
-
多个串联
var src1 = ''; var result1 = loadImg(src1); var src2 = ''; var result2 = loadImg(src2); result1.then(function (img1) { console.log('第一张图片加载'); return result2; }).then(function (img2) { console.log('第二张图片加载完成'); })
-
Promise.all和Promise.race
Promise.all接受一个promise对象的数组。待全部执行完后统一执行下一步。
var src1 = ''; var result1 = loadImg(src1); var src2 = ''; var result2 = loadImg(src2); Promise.all([result1, result2]).then(function (datas) { comsole.log('all', datas[0]); comsole.log('all', datas[1]); }) Promise.race([resutl1, result2]).then(function (data) { console.log('race', data); })
-
Promise标准
- 任何技术推广都需要一套标准来支撑
- 任何不符合标准的东西,终将会被用户抛弃
- 不要挑战标准,不要自造标准
状态变化
- 三种状态
- 初始状态:pending
- 不可逆
then
- promise实例必须实现then
- then必须接收两个参数作为参数,一个成功,一个失败
- 如果then里面的函数返回promise实例,那么下一个then就是执行这个实例。如果没有返回,下一个then就是执行原promise实例。
async/await
-
then只是将callback拆分开了
-
async/await是最直接的同步写法
const load = async function() { const result1 = await loadImg(src1); console.log(result1); const result1 = await loadImg(src1); console.log(result1); }
-
await必须和async一起使用
-
await后面跟的是一个promise实例
-
使用babel-polifill,兼容
-
基本语法。使用了promise,但是没有和Promise冲突。完全是同步的写法,再也没有回调函数。但是还是改变不了JS单线程,异步的本质。
来源:51CTO
作者:DadaxinBlog
链接:https://blog.csdn.net/huaxiaoduo1949101/article/details/100882578