promise的前世来生

匿名 (未验证) 提交于 2019-12-03 00:08:02

问题

  • 什么是单线程,和异步什么关系
  • 什么是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.donedtd.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单线程,异步的本质。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!