半明白系列–Promise的进化史
学过js的都晓得,顺序有同步编程和异步编程之分,同步就比方流水线,一步一个脚印,做完上个使命才做下一个,异步编程比方客服,客服接了一个电话,收到了一个使命,然后把使命交给别的的人来处置惩罚,同时,继承接听下一个电话,比及别的的人处置惩罚完使命了,再关照客服,客服再反馈给第一个打电话的人。异步编程平常用来调取接口拉数据。
经由过程我形貌的篇幅,就晓得异步编程比同步编程贫苦很多。太古时代,异步编程是经由过程回调函数来处理的。然则回调函数会有回调地狱的题目,回调的多了,保护职员看起来头都大了,比方:taskC须要守候taskB做完(taskC才实行),taskB又须要守候taskA做完(taskB才实行)
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)
promise的运用
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的静态要领
上面说的then
和catch
都是Promise的原型要领,即Promise.prototype.then/catch
Promise自身有两个静态要领,其作用类似 new Promise()
Promise.resolve()
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的链式挪用
Promise的实例对象的then要领是能够反复挪用的,then要领返回的是一个promise实例对象,所以能够反复挪用then要领,而且(敲黑板),上一个then要领的返回值,会作为下一个then要领的参数通报
举个栗子:
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啦