zoukankan      html  css  js  c++  java
  • 抄作业

    了解 Promise ?

    Promise 是一种异步编程的解决方案;有三种状态,pending (进行中)、resolved(已完成)、rejected(已失败)。当Promise的状态由 pending 转变为 resolved 或 rejected 时,会执行相应的方法。状态一旦改变,就无法再次改变状态。
    特点:Promise 的特点是只有异步操作的结果,可以决定当前是哪一种状态,其他操作都无法改变这个状态。

    Promise 解决的痛点是什么 ?

    • 多次异步调用的结果,顺序可能不同步
    • 异步调用的结果如果存在依赖,则需要嵌套
      在ES5中,当进行多层嵌套回调时,会导致代码层次过多,很难进行维护和二次开发;而且会导致回调地狱的问题。
    1. 解决了 回调地狱 的问题;
    2. **promise 可以支持多个并发的请求,获取并发请求中的数据 **
    3. promise 可以解决可读性的问题
    4. promise 可以解决信任问题;对于回调过早、回调过晚或没有调用和回调次数天少或太多,由于promise只能决议一次,决议值只能有一个,决议之后无法改变,任何then中的回调也只会被调用一次,所以这就保证了Promise可以解决信任问题

    Promise 解决的痛点还有其他方法可以解决吗? 如果有,请举例

    **Promise 解决的通电还有其他方法可以解决,比如 setTimeout,事件监听,回调函数,Generator函数,async/await **

    • setTimeout:缺点不精确,只能确保在一定时间后加入到任务队列,并不保证立马执行。只有执行引擎栈中的代码执行完毕,主线程才会取读取任务队列
    • 事件监听: 任务的执行不取决于代码的顺序,而取决于某个事件是否发生
    • Generator函数:虽然将异步操作表示的很简洁,但是流程管理却不方便(即何时执行第一阶段,何时执行第二阶段).

    Promise 的问题? 解决办法?

    问题

    1. promise 一旦执行,无法中途取消
    2. promise 的错误无法在外部被捕捉到,只能在内部进行预判处理
    3. promise 的内部如何执行,监测起来很难
      解决办法
      使用ES7引入的 async,await 来处理异步

    Promise 语法

    new Promise(function(resolve, reject){
    //...
    })
    Promise 的构造函数接收一个参数,是函数,并且传入两个参数 resolve 和 reject,分别表示异步操作执行成功后的回调函数 和 异步操作执行失败后的回调函数。

    Promise 的基本使用

    // 封装
    function returnAsync() {
    	var promise = new Promise((resolve, reject) => {
    		// 异步操作
    		setTimeout(() => {
    			console.log("执行完成")
    			let num = Math.ceil(Math.random()*10)
    			if( num <= 5 ) {
    				resolve(num); // 成功
    			} else {
    				reject("数字太大") // 失败
    			}
    		}, 1000)
    	})
    	return promise
    }
    // 使用方式一,在then添加两个参数,第一个表示成功回调,第二个表示失败回调
    returnAsync()
    .then((data) => {
    	console.log("成功回调", data)
    	console.log(newnum); // 此处的newnum未定义
    	// 使用第二个参数作为异常回调,会报错卡死JS
    }, (error) => {
    	console.log("失败回调", error)
    })
    
    // 使用方式二,catch的用法 (当then中有代码抛出异常时,并不会报错卡死js,而是会进到catch方法中,相当于我们的tyr/catch语句功能)
    returnAsync()
    .then((data) => {
    	console.log("成功回调", data)
    	console.log(newnum); // 此处的newnum未定义
    })
    .catch((error) => {
    	console.log("失败回调", error)
    })
    .finally(() => {
    	console.log("无论成功失败都会执行")
    })
    

    Promise 多次处理异步请求 (链式调用)

    实际开发场景一:
    同时请求多个接口,比如:在请求完 接口1 之后,需要根据接口1的数据继续请求接口2,以此类推...
    实际开发场景二:
    一个大的区域需要做一个Loading,后端分别给了好几个接口,此时需要全部请求完成之后才移除Loading

    // 封装发送请求函数,返回一个Promise
    function ajaxQuery(url) {
    	let promise = new Promise((resolve, reject) => {
    		var xhr = new XMLHttpRequest();
    		xhr.onreadystatechange = function () {
    			if(xhr.readyState != 4) return;
    			if(xhr.readyState == 4 && xhr.status == 200) {
    				// 处理正常情况
    				resolve(xhr.responseText);
    				// xhr.responseText 是从接口拿到的数据
    			} else {
    				// 处理异常情况
    				reject("接口请求失败")
    			}
    		}
    		xhr.responseType = 'json'; // 设置返回的数据类型
    		xhr.open('get', url)
    		xhr.send(null); // 请求接口
    	})
    	return promise;
    }
    
    // 使用: 发送多个ajax请求并且保持顺序
    ajaxQuery("http://localhost:3000/api1")
    .then((data1) => {
    	// 请求完接口1后,继续请求接口2
    	return ajaxQuery("http://localhost:3000/api2")
    })
    .then((data2) => {
    	// 请求完接口2后,继续请求接口3
    	return ajaxQuery("http://localhost:3000/api3")
    })
    .then((data3) => {
    	// 获取接口3返回的数据
    	console.log("接口3的数据", data3)
    })
    .catch((error) => {
    	console.log("异常:", error)
    })
    

    Promise回调函数的返回值

    两种情况:
    情况一: 返回Promise实例对象,返回的该实例对象会调用下一个 then

    Promise.resolve().then(() => 'Hello World!')
    .then((value) => {
    	console.log("fulfilled:", value); // Hello World!
    })
    .catch((value) => {
    	console.log("rejected:", value)
    })
    

    情况二: 返回普通值,返回的普通值会直接传递给下一个 then

    Promise.resolve().then(() => {
    	return Promise.resolve("Hello")
    })
    .then((value) => {
    	console.log("fulfilled:", value) // Hello
    })
    .catch((value) => {
    	console.log('rejected:', value)
    })
    

    Promise 常用API

    Promise.resolve(value)

    # 类方法,该方法返回一个以 value 值解析后的 Promise 对象
    # 普通值
    Promise.resolve([1, 2, 3])
    .then((value) => {
    	console.log(value) // [1,2,3]
    })
    
    # 另一个promise
    let otherPromise = Promise.resolve(33)
    Promise.resolve(otherPromise)
    .then((value) => {
    	console.log(value) // 33
    })
    

    Promise.reject()

    # 类方法,且与resolve唯一的不同是,返回的promise对象的状态为rejected
    function asyncPromise() {
    	try {
    		console.log(newNum); // 未定义,会走catch
    		return Promise.resolve(100);
    	} catch (error) {
    		return Promise.reject(error)
    	}
    }
    // 使用
    asyncPromise()
    .then((value) => {
    	// newNum未定,则走catch,如果去掉这返回 100
    	console.log(value)
    })
    .catch((error) => {
    	// error ReferenceError: newNum is not defined
    	console.log(error)
    })
    

    Promise.prototype.then
    实例方法,为Promise注册回调函数,fn().then((value) => {}),value 是上一个任务的返回结果,then中的函数一定要 return 一个结果 或者一个新的 Promise 对象,才可以让之后的 then回调接收
    Promise.prototype.catch
    实例方法,捕获异常,fn().catch((error) => {}), error 是 catch 注册之前的回调抛出的异常信息
    Promise.race()

    # 类方法,多个Promise 任务同时执行,返回最先执行结束的 Promise 任务结果,不管这个 Promise 结果是成功还是失败  
    let p1 = new Promise((resolve, reject) => {
    	setTimeout(resolve, 500, 'one')
    })
    let p2 = new Promise((resolve, reject) => {
    	setTimeout(resolve, 100, 'two')
    })
    Promise.race([p1, p2]).then((value) => {
    	console.log(value) // 两个都完成 two 最快
    })
    # 注意:使用场景可以用于 提示网络不佳等
    

    Promise.all()

    # 类方法,多个Promise任务同事执行。如果全部完成执行,则以数组的方式返回所有Promise任务的执行结果。只要任何一个输出的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息    
    
    let p1 = Promise.resolve(10)
    let p2 = 1773
    let new Promise((resolve, reject) => {
    	setTimeout(resolve, 100, 'foo')
    })
    Promise.all([p1, p2, p3])
    .then((values) => {
    	console.log(values); // [10, 1773, "foo"]
    })
    

    问题:为什么 promise 需要引入微任务?

    Promise 中的执行函数是同步进行的,但是里面存在着异步操作,在异步操作结束后会调用 resolve 方法, 或者中途遇到错误调用reject 方法,这两者都是作为微任务进入到 EventLoop 中。但是你有没有想过, Promise 为什么要引入微任务的方式来进行回调操作?
    若 promise 回调放在进行宏任务队列的尾部,若队列非常长,那么回调迟迟得不到执行,造成的效果就是应用卡顿。所以就引入了微任务
    将回调函数放到当前宏任务中的最后面。
    这样,利用微任务解决了两大痛点:

    1. 采用异步回调替代同步回调解决了浪费 CPU 性能的问题
    2. 放在当前宏任务最后执行,解决了回调执行的实时性问题
  • 相关阅读:
    在Linux上使用C语言编程获取IPv4地址及子网掩码
    使用gdb进行写操作
    [中英对照]The Art Of Reporting Bugs | 报bug的艺术
    [中英对照]Introduction to Remote Direct Memory Access (RDMA) | RDMA概述
    Intel万兆网卡背靠背连接ping不通那点事儿
    [中英对照]The sysfs Filesystem | sysfs文件系统
    图说单播,组播,广播,选播和地域播
    Ubuntu双网卡不双待攻略
    反汇编容易反编译难
    PHP之路——微信公众号授权获取用户信息
  • 原文地址:https://www.cnblogs.com/yuxi2018/p/14469580.html
Copyright © 2011-2022 走看看