学过js的都知道,程序有同步编程和异步编程之分,同步就比如流水线,一步一个脚印,作完上个任务才作下一个,异步编程比如客服,客服接了一个电话,收到了一个任务,而后把任务交给另外的人来处理,同时,继续接听下一个电话,等到另外的人处理完任务了,再通知客服,客服再反馈给第一个打电话的人。异步编程通常用来调取接口拉数据。html
经过我描述的篇幅,就知道异步编程比同步编程麻烦许多。远古时期,异步编程是经过回调函数来解决的。可是回调函数会有回调地狱的问题,回调的多了,维护人员看起来头都大了,比如:taskC须要等待taskB作完(taskC才执行),taskB又须要等待taskA作完(taskB才执行)es6
function taskA (cb) { //..do task A cb() } function taskB(cb){ //..do task B cb() } function taskC(cb){ //..do task C cb() } taskA(function(){ taskB(function(){ taskC() }) }) ...以此类推,不断循环嵌套,最终陷入地狱
而Promise就把这一系列的回调,经过链式调用的方式链接起来,看起来清爽多了。一样是上面的代码,Promise能够这么写(伪代码)编程
new Promise().then(taskA).then(taskB).then(taskC)
const promise = new Promise((resolve,reject)=>{ if (/*do something done*/){ resolve() // 可在此传参数 } else { // do something fail reject() // 可在此传参数 } }) promise.then(()=>{ //do something }).catch(e => { throw e})
上面的resolve
,能够看成task函数的cb回调函数,当resolve()
执行的时候,then
方法中的回调会被执行,若是是reject
执行,错误会被catch
捕捉。promise
Promise的静态方法异步
上面说的then
和catch
都是Promise的原型方法,即Promise.prototype.then/catch
Promise自己有两个静态方法,其做用相似 new Promise()
Promise.resolve()async
const promise1 = Promise.resolve() 等价于 const promise2 = new Promise((reslove)=>{ reslove() })
使用该方法调用then
方法
Promise.reject()异步编程
const promise1 = Promise.reject() 等价于 const promise2 = new Promise((resolve,reject)=>{ reject() })
使用该方法会被catch
捕捉函数
Promise的链式调用this
Promise的实例对象的then方法是能够重复调用的,then方法返回的是一个promise实例对象,因此能够重复调用then方法,而且(敲黑板),上一个then方法的返回值,会做为下一个then方法的参数传递google
举个栗子:
const promise = Promise.resolve('start') promise.then((params)=>{ console.log(params) // start return 'aa' }).then((params) => { console.log(params) // aa return 'bb' }).then((params)=>{ console.log(params) // bb return 'cc' }) // 最后会返回一个状态是resolve(cc)的promise对象:Promise {<resolved>: "cc"}
深刻一下(又不会怀孕)
function badAsyncCall() { var promise = Promise.resolve(); promise.then(function() { // 任意处理 return 'newVar'; }); return promise; } // 修改一下 function goodAsyncCall() { var promise = Promise.resolve(); return promise.then(function() { // 任意处理 return 'newWar'; }); }
以上两个写法是否是很类似,惟一不一样的就是return的处理。但调用,badAsynccall
会出错,而anAsyncCall
能正确执行,好比:
badAsyncCall().then(params => { console.log('bad--',params)}) // bad-- undefined goodAsyncCall().then(params => { console.log('good--',params)}) // good-- newWar
分析:第一种,错误写法,首先在 promise.then 中产生的异常不会被外部捕获,此外,也不能获得 then 的返回值,即便其有返回值。
缘由:因为每次 promise.then 调用都会返回一个新建立的promise对象,第一种返回的promise,至关于没有调用过函数内部的then方法,是一个全新的promise实例对象
结论: 统一使用promise链式调用,如:promise.then(taskA).then(taskB)
### async&await和promise的前世缘缘
promise说白了仍是用回调的方式来解决异步问题,跟真正同步仍是有差距的。
异步编程的最高境界,就是根本不用关心它是否是异步!(来之ruanyifeng老师的话)
因此,async&await方案出现了
用法:
function readFile(fileName) { return new Promise((resolve,reject)=>{ fs.readFile(fileName, function(error, data) { if (error) return reject(error); resolve(data); // 向thenc传送异步读取文件的数据 }); }) } // 调用 readFile(fileName).then(function(data){ console.log('prmoise read files data --', data) }) // 等价于 async function asyncFn(fileName){ const data = await readFile(fileName) console.log('await data --', data) return data } asyncFn(fileName)
写法是否是简洁了许多!
其实async就是一个Promise的语法糖,它的返回值是一个promise对象,所以能够用then方法作链式调用(但参数就是async函数中的返回值,如上文的data!!)
async函数中还能够不使用promise,好比:
async function asyncFn(){ const data = await setTimeout(function(){ console.log('setTimeout') return 'data' },1000) console.log('data',data) // Timeout {} 对象 } console.log('async',asyncFn()) // Promise { <pending> }
但这二者,其实常常混用,常见的就是readFile函数的作法啦
看懂以上的,才你们出一道题看看能不能懂;
async function asynFn(){ await Promise.resolve('aaa') const data = { b:'bb', c:function(){ return this.b } } return data //return 做为参数传递给then then的chain链也是经过return参数来不断传递给后面的then } var cball = asynFn() cball.then(function(data){ console.log('data:',data) })
还有一种异步编程的语法糖: * & yield
跟async基本同样,不在本文讨论的重点。有兴趣自行google啦