大家都知道nodejs很快,原因就是node采用异步回调的方式来处理需要等待的事件,使得代码会继续往下执行不用在某个地方等待着。但是也有一个不好的地方,当我们有很多回调的时候,比如这个回调执行完需要去执行下个回调,然后接着再执行下个回调,这样就会造成层层嵌套,代码不清晰,很容易进入“回调监狱”,就容易造成下边的例子:
请求1(function(请求结果1){ 请求2(function(请求结果2){ 请求3(function(请求结果3){ 请求4(function(请求结果4){ 请求5(function(请求结果5){ 请求6(function(请求结果3){ ... }) }) }) }) }) })这样的写法代码缺点很多。es6新出的promise对象已经es7的async await都可以解决这个问题,当然这里先介绍promise对象,es7的async await将在后边的文章中分享。下边将来介绍Promise对象。
Promise 是异步编程的一种解决方案,比传统的异步解决方案【回调函数】和【事件】更合理、更强大。现已被 ES6 纳入进规范中。
Promise,他是一个对象,是用来处理异步操作的,可以让我们写异步调用的时候写起来更加优雅,更加美观便于阅读。顾名思义为承诺、许诺的意思,意思是使用了Promise之后他肯定会给我们答复,无论成功或者失败都会给我们一个答复,所以我们就不用担心他跑了哈哈。
所以,Promise有三种状态:pending(进行中),resolved(完成),rejected(失败)。只有异步返回的结构可以改变其状态。
所以,promise的过程一般只有两种:pending->resolved或者pending->rejected。
此时,promise用来解决的问题:
回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象promise可以支持多个并发的请求,获取并发请求中的数据注意:这个promise可以解决异步的问题,本身不能说promise是异步的
只有当resolve,reject才会执行then中的方法,执行resolve成功时,会调用.then方法,reject会执行err.
Promise的构造函数接收一个参数:函数,并且这个函数需要传入两个参数:
resolve :异步操作执行成功后的回调函数reject:异步操作执行失败后的回调函数它们的作用其实就是返回一个Promise对象,我们来实现一下。
resolve //resolve方法 Promise.resolve = function(val){ return new Promise((resolve,reject)=>{ resolve(val) }) } reject //reject方法 Promise.reject = function(val){ return new Promise((resolve,reject)=>{ reject(val) }) }Promise.prototype.then
该实例方法挂到原型上的,为 Promise 注册回调函数,函数形式:fn(vlaue){},value 是上一个任务的返回结果,then 中的函数一定要 return 一个结果或者一个新的 Promise 对象,才可以让之后的then 回调接收。
let fs = require("fs") function readFile(...args){ return new Promise((resolve,reject)=>{ fs.readFile(...args,function(err,data){ if(err) reject(err) resolve(data) }) }); } // 这样写不优雅, 又回到了回调地域 XXXXXXXXXXXX readFile("./name.txt","utf8").then(data=>{ // console.log(data) // age.txt readFile(data,"utf8").then(data=>{ console.log(data) // 666 },err=>{ console.log(err) }) },err=>{ console.log(err) })所以 .then 后面还可以 .then ,其实.then之后又返回了一个新的promise,而新的promise又可以.then了。 并且下一个.then中的data时上一个.then中的return data.err也是一样的。
let fs = require("fs") function readFile(...args){ return new Promise((resolve,reject)=>{ fs.readFile(...args,function(err,data){ if(err) reject(err) resolve(data) }) }); } // 如果返回的是一个promise,那么这个promise会执行,并且会采用它的状态 readFile("./name.txt","utf8").then(data=>{ // return data; return readFile(data,"utf8") return readFile(data,"utf8") },err=>{ return err; }).then(data=>{ console.log(data) // 666 },err=>{ console.log(err) })链式调用 如果在上一个then的第一个函数中,返回一个普通值,会走到下一个then的第1个函数,return的值作为这个then的data 如果返回的是一个promise,会作为下一个then的promise对象,data err去promise对象中取
该方法是挂在Promise原型上的方法。当我们调用catch传callback的时候,就相当于是调用了then方法。
let p = new Promise((resolve,reject)=>{ resolve("OK") }) // catch就.then的语法糖 // 最终,一个promise中,一般在then中只有一个函数,在then后面有一个catch,一般使用then来获取data,在catch中获取err p.then(data=>{ console.log(data) }).catch(err=>{ console.log(err) })all方法可以说是Promise中很常用的方法了,它的作用就是将一个数组的Promise对象放在其中,当全部resolve的时候就会执行then方法,当有一个reject的时候就会执行catch,并且他们的结果也是按着数组中的顺序来排放的,那么我们来实现一下。
let Promise1 = new Promise(function(resolve, reject){}) let Promise2 = new Promise(function(resolve, reject){}) let Promise3 = new Promise(function(resolve, reject){}) let p = Promise.all([Promise1, Promise2, Promise3]) p.then(funciton(){ // 三个都成功则成功 }, function(){ // 只要有失败,则失败 })顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
原理: //race方法 Promise.race = function(promises){ return new Promise((resolve,reject)=>{ for(let i=0;i<promises.length;i++){ promises[i].then(resolve,reject) } }) } 用法: let fs = require("fs").promises; Promise.race([fs.readFile("./name.txt","utf-8"),fs.readFile("./age.txt","utf-8")]).then(data=>{ console.log(data) // age.txt })Promise是一个类,使用之前需要new ,在new的时候,返回的一个promise对象,需要给Promise传递一个执行器。这个执行器会立即执行。
在执行器中有两个参数:resolve,reject,是函数,就可以把promise从等待状到成功或失败。 promise有一个then方法,如果到成功状,它会调用then中的第1个函数 如果失败了,它会调用then中的第2函数。 在then中第1个函数的参数就是成功的结果, 在then中第2个函数就的参数就是失败的结果
大家可以搜下pormise的面试题,坐下参考:其中可能比较重要的要能手写一个简单的promise了。 下面也是我在网上找的面试点,大家共同学习:
1、了解 Promise 吗?2、Promise 解决的痛点是什么?3、Promise 解决的痛点还有其他方法可以解决吗?如果有,请列举。4、Promise 如何使用?5、Promise 常用的方法有哪些?它们的作用是什么?6、Promise 在事件循环中的执行过程是怎样的?7、Promise 的业界实现都有哪些?8、能不能手写一个 Promise 的 polyfill。参考链接:https://juejin.im/post/5afe6d3bf265da0b9e654c4b#heading-5
https://juejin.im/post/5afe6d3bf265da0b9e654c4b#heading-7