Promises/A+規(guī)范文檔
Promises/A+規(guī)范文檔中文翻譯
Promise標(biāo)準(zhǔn):
- 擁有一個(gè)then方法
- fulfill 成功時(shí)的操作,即resolve
- reject 失敗時(shí)的操作
- padding 等待
一個(gè)簡(jiǎn)單的promise流程
function Promise(fn) {
var value = null
var callback = []
this.then = function(onFulfilled){
callbacks.push(onFulfilled)
}
function resolve(value){
callbacks.forEach(function(callback){
value = callback(value)
})
}
fn(resolve)
}
new Promise(
function(resolve){
setTimeout(()=>{
console.log(123)
return resolve(6)
},1000)
}
).then(
(v)=>{
console.log('1',v)
return v
}
)
// 一秒鐘后
// 123
// 1 6
上述代碼很簡(jiǎn)單,大家肯定都能看得懂懂更。
- 將then方法掛載到callbacks隊(duì)列
- 創(chuàng)建的promise實(shí)例傳入的函數(shù)會(huì)被賦予resolve參數(shù)富玷,resolve能啟動(dòng)callbacks隊(duì)列耘斩,當(dāng)異步函數(shù)執(zhí)行完時(shí)磁携,將結(jié)果給resolve酌摇,resolve就能帶著這個(gè)結(jié)果啟動(dòng)callbacks轧简,執(zhí)行then函數(shù)驰坊。
不難發(fā)現(xiàn),then是需要鏈?zhǔn)秸{(diào)用的哮独,總所周知鏈?zhǔn)秸{(diào)用也很簡(jiǎn)單拳芙,只需要添加 return this
即可
修改如下
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
return this;
};
這個(gè)時(shí)候我們刪掉定時(shí)器,突然發(fā)現(xiàn)皮璧, 123
正常輸出舟扎,但是1 6
并沒有輸出,為什么呢悴务?睹限?這是因?yàn)椋潭际峭窖堕埽?dāng)我們執(zhí)行resolve的時(shí)候羡疗,then還沒有掛載到隊(duì)列上面。根據(jù)js執(zhí)行機(jī)制别洪,我們可以加一個(gè)setTimeout 叨恨,setTimeout是異步函數(shù),屬于宏任務(wù)挖垛,會(huì)放在任務(wù)最后痒钝。將resolve中執(zhí)行回調(diào)的邏輯放在任務(wù)隊(duì)列末尾,以保證resolve時(shí)晕换,then方法已經(jīng)全部掛載完畢即可午乓。
function resolve(value) {
setTimeout(function() {
callbacks.forEach(function (callback) {
value = callback(value);
});
}, 0)
}
這是個(gè)時(shí)候可能我們又發(fā)現(xiàn)
new Promise(
function(resolve){
setTimeout(()=>{
console.log(123)
return resolve(6)
},1000)
}
).then(
(v)=>{
console.log('1',v)
return v
}
).then(
setTimeout((v)=>{
console.log('3', v)
},1000)
)
// 123
// 1 undefined
// 1 6
// Uncaught TypeError: callback is not a function
我們需要優(yōu)化resolve方法
function resolve(value) {
setTimeout(()=>{
callbacks.forEach(function (callback) {
if (typeof callback === 'function') {
value = callback(value)
}
});
},0)
}
加入狀態(tài)
pending
,fulfilled
,rejected
function Promise(fn) {
let value = null
let callbacks = []
let state = 'pending'
this.then = function (onFulfilled) {
if(state==='pending'){
callbacks.push(onFulfilled);
return this;
}
onFulfilled(value)
return this
};
function resolve(value) {
state = 'fulfilled'
setTimeout(()=>{
callbacks.forEach(function (callback) {
if (typeof callback === 'function') {
value = callback(value);
}
});
},0)
}
fn(resolve);
}
function Promise1(fn) {
var state = 'pending'
var value = null
var callbacks = []
this.then = function (onFulfilled, onRejected) {
return new Promise1(function (resolve, reject) {
handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
})
})
}
function handle(callback){
console.log(state)
if(state === 'pending'){
callbacks.push(callback)
return
}
console.log(state)
var cb = state === 'fulfilled' ? callback.onFulfilled : callback.onRejected
var ret
if(cb === null){
cb = state === 'fulfilled' ? callback.onFulfilled : callback.onRejected
cb(value)
return
}
try{
ret = cb(value)
console.log('ret',ret)
callback.resolve(ret)
}catch(e){
callback.reject(e)
}
}
function resolve(newValue){
if(newValue && (typeof newValue === 'object' || typeof newValue === 'function')){
console.log('function')
var then = newValue.then
if(typeof then ==='function'){
then.call(newValue,resolve,reject)
return
}
}
console.log('nofunction')
state = 'fulfilled'
value = newValue
execute()
}
function reject(reason){
state = 'rejected'
value = reason
execute()
}
function execute(){
setTimeout(function(){
callbacks.forEach(function(callback){
handle(callback)
})
},0)
}
fn(resolve,reject)
}