贵州省和城乡建设厅官方网站,网络信息推广服务,html怎么弄,策划推广方案浅谈对Promise的理解以及在工作中的应用Promise的概念背景知识JavaScript的同步和异步JavaScript事件循环回调函数进行异步操作解决方案#xff1a;PromisePromise 在工作中的运用创建PromisePromise封装AJAXPromise链式操作Promise.all()Promise.race()async和await总结Promi…
浅谈对Promise的理解以及在工作中的应用Promise的概念背景知识JavaScript的同步和异步JavaScript事件循环回调函数进行异步操作解决方案PromisePromise 在工作中的运用创建PromisePromise封装AJAXPromise链式操作Promise.all()Promise.race()async和await总结Promise的概念
在开始讲解Promise前我们先大致了解一下js的运行机制以及多个任务是怎么运作的。
背景知识
众所周知JavaScript是一门单线程语言也就意味着所有任务需要排队前一个任务结束才会执行后一个任务。如果前一个任务耗时很长后一个任务就不得不一直等着这样会造成浏览器处于假死状态严重影响用户体验。为了解决这个问题js引入了异步的概念在执行任务时挂起处于等待中的任务先运行排在后面的任务。等到刚才挂起的任务返回了结果再回过头把挂起的任务继续执行下去。于是js将所有的任务分成了两种一种是同步任务synchronous另一种是异步任务asynchronous。
JavaScript的同步和异步
同步任务指的是在主线程上排队执行的任务只有前一个任务执行完毕才能执行后一个任务
异步任务指的是不进入主线程、而进入任务队列task queue的任务只有任务队列通知主线程某个异步任务可以执行了该任务才会进入主线程执行 除了广义的同步任务和异步任务对任务更精细的定义:
宏任务(macro-task)包括整体代码scriptsetTimeoutsetInterval 微任务(micro-task)Promiseprocess.nextTick
宏任务中有微任务一定要将宏任务中的微任务执行完毕再去执行下一个宏任务。 那究竟什么是任务队列呢同步任务和异步任务又是怎么执行的这就要引入js的运行机制事件循环(event loop)
JavaScript事件循环 js事件循环运作机制如下
同步任务和异步任务分别进入不同的“场所”同步任务进入主线程异步任务进入Event Table (事件表)并注册函数指定的事件完成后Event Table (事件表)会将这个函数移入到Event Queue (事件队列)当主线程的任务完成后会检查Event Queue (事件队列)如果有任务就全部执行如果没有就进入下一个宏任务这个过程会不断的重复这就叫事件循环
回调函数进行异步操作
和同步操作不同异步操作是不会立即返回结果的如发起网络请求下载文件操作数据库等。如果我们后续的函数需要之前返回的结果又怎样使之前的异步操作在其完成时通知到后续函数来执行呢
通常我们可以将这个函数先定义存储在内存中将其当做参数传入之前的异步操作函数中等异步操作结束就会调用执行这个函数这个函数就叫做回调函数callback
// 下载
function download(callback){// 模拟异步操作setTimeout(function(){// 调用回调函数callback(下载完成);}, 1000);
}function callback(value){// 下载完成的处理console.log(value);
}download(callback);// 这段代码将在1秒后在控制台打印“下载完成”但假如callback函数同样是个异步函数且callback里又嵌入了callback呢 例如需求是等待第一个文件下载完成后再下载第二个文件等待第二个文件下载完成后再下载第三个文件…这样的话上面这种方法就不可取了因为会产生很多的函数嵌套嵌套太深容易引发回调地狱指的是回调函数里嵌套回调函数使得代码可读性非常差容易陷于无止尽的循环 //回调地狱setTimeout(function () { //第一层console.log(张三);//等3秒打印张三在执行下一个回调函数setTimeout(function () { //第二层console.log(李四);//等2秒打印李四在执行下一个回调函数setTimeout(function () { //第三层console.log(王五);//等一秒打印王五}, 1000)}, 2000)}, 3000)解决方案Promise
所以为了回调地狱的问题promise方案应运而生它是对回调方法的一种封装是用来处理异步操作的可以让我们写异步调用的时候写起来更加优雅更加美观。 以下是promise的一些特点
Promise 对象代表一个异步操作对象的状态不受外界影响有三种状态pending进行中、fulfilled已成功、rejected已失败、settled 结束只有异步操作的结果可以决定当前是哪一种状态任何其他操作都无法改变这个状态且一旦状态改变就不可再变Promise对象的then方法用来接收处理成功时响应的数据catch方法用来接收处理失败时相应的数据其中then方法的两个参数是resolve成功回调reject失败回调。异步任务执行成功时调用resolve函数返回结果反之调用reject根据不同的任务由开发者来决定resolve和reject在函数体内的位置then方法返回的是一个新的Promise实例注意不是原来那个Promise实例。因此可以采用链式写法即then方法后面再调用另一个then/catch方法链式调用可以保证代码的执行顺序 promise解决刚才的地狱回调问题
// promise解决方式
function fn(str) {var promise new Promise(function (resolve, reject) { //resolve是成功的方法 reject是失败的方法 //处理异步任务var flag true;setTimeout(function () {if (flag) {resolve(str)}else {reject(失败)}})})return promise;
}fn(张三).then((res) { //then是成功执行的方法 返回的还是一个promise对象console.log(res);//打印张三 res是结果return fn(李四);}).then((res) {console.log(res);return fn(王五)}).then((res) {console.log(res);}).catch((res) { //catch是失败执行的方法console.log(res);})Promise 在工作中的运用
创建Promise
promise构造器只接收一个参数该参数被称为执行器executor的函数。该函数会被传递两个参数方法一个叫做resolve另一个叫做reject。
resolve函数在成功时调用reject函数在失败时被调用。并且resolve和reject只能被使用一次如果之后还有resolve和reject也不会被执行了有点儿类似于return但是不同点在于其他代码还会被照常执行。
new Promise((resolve, reject) {resolve(我是第一次调用resolve);console.log(我是其他代码);resolve(我是第二次调用resolve); // 不在起作用reject(我来调用reject); // 不在起作用
})也可以直接使用Promise.resolve或者Promise.reject来创建成功或者失败的Promise
let p1 Promise.resolve(我是成功的Promise),p2 Promise.reject(我是失败的Promise);Promise封装AJAX
var ajax function(url) {return new Promise(function(resolve, reject) {var xhr new XMLHttpRequest();xhr.open(get, url, true);xhr.send();xhr.onreadystatechange function() {if (xhr.readystate 4 xhr.status 200) {resolve(xhr.responseText)} else if (xhr.readystate 4 xhr.status ! 200) {reject(xhr.statusText)}}})
}
ajax.then(console.log(xhr.responseText)); //打印出返回的数据
Promise链式操作
由于Promise的then 方法始终返回一个 Promise 对象, 所以Promise 可以一直调用 then 方法从而实现链式调用解决地狱回调。不管 new Promise 创建出来的执行状态是成功 / 失败只要在 then / catch方法中通过 return 返回一个结果不管这个值是 Promise 对象还是普通值都可以通过链式调用的 .then 方法中获取到这个值因为 promise.then 方法会默认在返回值的外层包裹一层 Promise 对象这样才可以实现 Promise 一直通过 .then 的方式去链式调用
let p1 new Promise((resolve, reject) {let name 张三setTimeout(() {resolve(name);}, 2000)
})let p2 new Promise((resolve, reject) {let name 李四setTimeout(() {resolve(name);}, 1000)
})let p3 new Promise((resolve, reject) {let name 王五setTimeout(() {resolve(name);}, 3000)
})//方式一链式操作返回promise对象
p1.then((res) {console.log(res第一个出场);return p2
}).then((res) {console.log(res第二个出场);return p3
}).then((res) {console.log(res第三个出场);
})//链式操作返回promise对象输出结果
张三第一个出场
李四第二个出场
王五第三个出场//方式二链式操作返回普通值
p1.then((res) {console.log(我是res);return res
}).then((res) {console.log(我是res的儿子);return res
}).then((res) {console.log(我是res的孙子);
})//链式操作返回普通值输出结果
张三第一个出场
李四第二个出场
王五第三个出场Promise.all()
这个方法返回一个新的promise对象该promise对象在参数对象promises里所有的promise对象都成功的时候才会触发成功一旦有任何一个promises里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后会把一个包含promises里所有promise返回值的数组作为成功回调的返回值顺序跟promises的顺序保持一致如果这个新的promise对象触发了失败状态它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。 简而言之all方法会将传入的异步操作并行执行等到它们都执行完后才会进到then方法从时间上来看取决于最后一个异步任务执行完成的时间
let p1 new Promise((resolve, reject) {let name 张三setTimeout(() {resolve(name);}, 2000)
})let p2 new Promise((resolve, reject) {let name 李四setTimeout(() {resolve(name);}, 1000)
})let p3 new Promise((resolve, reject) {let name 王五setTimeout(() {resolve(name);}, 3000)
})// promise.all用法
Promise.all([p1,p2,p3]).then((res) {console.log(res都已到达终点);
})// promise.all输出结果
张三,李四,王五都已到达终点Promise.race()
race就是赛跑的意思谁先出结果就由谁决定采用第一个 promise 的值作为它的值当promises参数里的任意一个子promise被成功或失败后父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄并返回该promise对象。
let p1 new Promise((resolve, reject) {let name 张三setTimeout(() {resolve(name);}, 2000)
})let p2 new Promise((resolve, reject) {let name 李四setTimeout(() {resolve(name);}, 1000)
})let p3 new Promise((resolve, reject) {let name 王五setTimeout(() {resolve(name);}, 3000)
})// promise.race用法
Promise.race([p1,p2,p3]).then((res) {console.log(res第一个到达终点);
})// promise.all输出结果
李四第一个到达终点async和await
async 是“异步”的简写而 await 可以认为是 async wait等待 的简写。 所以应该很好理解 async 用于申明一个 function 是异步的返回的是一个 Promise 对象. 而 await 用于等待一个异步方法执行完成后面必须跟一个Promise对象但是不必写then()直接就可以得到返回值 //基本用法的async函数
let asyncFun async function(){return 1
}
console.log(asyncFun())
//会返回一个promise对象//使用场景
//摇色子方法
function dice(){return new Promise((resolve,reject){let sino parseInt(Math.random()*61) //生成一个1~6之间的随机小数setTimeout((){resolve(sino)},2000)})
}
//异步方法async function text(){let n await dice()//await 关键字后面调用摇色子方法执行完毕之后才进行变量赋值console.log(摇出来n) //最后打印出摇出来的数}
text()//输出结果
Promise { 1 }
摇出来5总结
以上就是我个人关于Promise的理解以及在工作中的应用总的来说Promise在日常开发工作中的使用还是比较多的他最大的用途在于让多个异步的任务按照我们想要的方式去执行。但想要彻底理解promise的运行方式及原理还需要了解js引擎的运行逻辑任务队列、宏任务微任务等。上文中如果有错误的地方欢迎指正大家共同进步越秃越强