promise

JavaScript所有代碼都是單線程執(zhí)行的,所以avaScript的所有網(wǎng)絡(luò)操作援奢,瀏覽器事件蓖谢,都必須是異步執(zhí)行根吁。異步執(zhí)行可以用回調(diào)函數(shù)實(shí)現(xiàn)
Js 的異步提高了程序的執(zhí)行效率,同時(shí)也減少了程序的可讀性端盆。


回調(diào)陷阱

異步操作會在將來的某個(gè)時(shí)間點(diǎn)觸發(fā)一個(gè)函數(shù)調(diào)用
AJAX就是典型的異步操作

es6 promise

Promise有各種開源實(shí)現(xiàn)怀骤,在ES6中被統(tǒng)一規(guī)范费封,由瀏覽器直接支持。
promiseA+規(guī)范中文 英文

// promise用法
new Promise(function (resolve, reject) {
    log('start new Promise...');
    var timeOut = Math.random() * 2;
    log('set timeout to: ' + timeOut + ' seconds.');
    setTimeout(function () {
        if (timeOut < 1) {
            log('call resolve()...');
            resolve('200 OK');
        }
        else {
            log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}).then(function (r) {
    log('Done: ' + r);
}).catch(function (reason) {
    log('Failed: ' + reason);
});
// promise all
var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
// 同時(shí)執(zhí)行p1和p2蒋伦,并在它們都完成后執(zhí)行then:
Promise.all([p1, p2]).then(function (results) {
    console.log(results); // 獲得一個(gè)Array: ['P1', 'P2']
});
// promise race
var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
    console.log(result); // 'P1'
});
同步回調(diào)和異步回調(diào)
// 同步回調(diào)
var arr = [1,2,3];

arr.forEach(function (x) {
  console.log('first');
});

console.log('last');

// first first first
// last
// 異步回調(diào)
setTimeout(function () {
  console.log('last')
}, 1000);

console.log('first');

// first
// last
實(shí)現(xiàn)一個(gè)簡單的promise

promiseA+規(guī)范的內(nèi)容

  • Promise 本質(zhì)是一個(gè)狀態(tài)機(jī)弓摘。每個(gè) promise 只能是 3 種狀態(tài)中的一種:pending、fulfilled 或 rejected痕届。狀態(tài)轉(zhuǎn)變只能是 pending -> fulfilled 或者 pending -> rejected衣盾。狀態(tài)轉(zhuǎn)變不可逆。
  • then 方法可以被同一個(gè) promise 調(diào)用多次爷抓。
  • then 方法必須返回一個(gè) promise势决。規(guī)范里沒有明確說明返回一個(gè)新的 promise 還是復(fù)用老的 promise(即 return this),大多數(shù)實(shí)現(xiàn)都是返回一個(gè)新的 promise蓝撇,而且復(fù)用老的 promise 可能改變內(nèi)部狀態(tài)果复,這與規(guī)范也是相違背的。

創(chuàng)建MyPromise類并根據(jù)規(guī)范初始化狀態(tài)


image.png

promise的鏈?zhǔn)秸{(diào)用


image.png
實(shí)現(xiàn)一個(gè)
const log = console.log;

// 1.創(chuàng)建類
class MyPromise {
    constructor(executor) {
        // 2.等待狀態(tài)
        this.status = "pending";
        // 初始化data
        this.data = undefined;
        // 初始化reason
        this.reason = undefined;
        // 3.執(zhí)行函數(shù)executor渤昌,定義我們的resolve虽抄,reject回調(diào)
        let resolve = (data) => {
            // log('resolve executor: '+ data);
            // 為了防止多次改變狀態(tài)
            if(this.status === 'pending') { 
               this.status = 'resolved'
                this.data = data;
                this.onFulFilledCallbacks.forEach((fn) => {
                   fn()
                })
            }
        }
        let reject = (reason) => { 
           // 為了防止多次改變狀態(tài)
            if(this.status === 'pending') {
                this.status = 'rejected'
                this.reason = reason;
                this.onRejectedCallbacks.forEach((fn) => {
                   fn()
                })
            }
        }

        // 5.儲存fulfilled的回調(diào)
        this.onFulFilledCallbacks = [];
        this.onRejectedCallbacks = [];

        try {
            executor(resolve, reject);
        } catch(err) {
            reject(err);
        }
    }
    // 4. MyPromise原型上的then方法
    then (onFulFilled, onRejected) {
        // log('then executor');
        // 處理無參數(shù)時(shí)的問題(值穿透)
        onFulFilled = typeof onFulFilled === 'function' ? onFulFilled : function(value) {return value};
        // 拋出錯(cuò)誤直接丟到下一個(gè)then中
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };

        let promise2;
        // 由于 promise.then 執(zhí)行的時(shí)候promise對象已經(jīng)是確定狀態(tài),從程序上說對回調(diào)函數(shù)進(jìn)行同步調(diào)用也是行得通的独柑。
        // 但是即使在調(diào)用 promise.then 注冊回調(diào)函數(shù)的時(shí)候promise對象已經(jīng)是確定的狀態(tài)迈窟,
        // Promise也會以異步的方式調(diào)用該回調(diào)函數(shù),這是在Promise設(shè)計(jì)上的規(guī)定方針忌栅。

        if(this.status === 'resolved'){
            promise2 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        let x = onFulFilled(this.data);
                        // log('onFulFilled return  value : '+x)
                        resolvePromsie(promise2, x, resolve, reject);
                    } catch (err) {
                        reject(err);
                    }
                }, 0);
            })
        }
        if(this.status === 'rejected'){
            promise2 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        // If either onFulfilled or onRejected returns a value x,
                         // run the Promise Resolution Procedure [[Resolve]](promise2, x).
                        let x = onRejected(this.reason);
                        resolvePromsie(promise2, x, resolve, reject);
                    } catch (err) {
                        reject(err);
                    }
                }, 0)
            })
        }
        if(this.status === 'pending'){
            // 這里要做一件很有意思的事车酣。。索绪。湖员。
            promise2 = new MyPromise((resolve, reject) => {
                // 將回調(diào)放在數(shù)組中等待調(diào)用
                this.onFulFilledCallbacks.push(() => {
                    process.nextTick(() => {
                        try {
                            let x = onFulFilled(this.data);
                            resolvePromsie(promise2, x, resolve, reject);
                        } catch (err) {
                            reject(err);
                        }
                    })
                  })
                this.onRejectedCallbacks.push(() => {
                    process.nextTick(() => {
                        try {
                            let x = onRejected(this.reason);
                            resolvePromsie(promise2, x, resolve, reject);
                        } catch (err) {
                            reject(err);
                        }     
                    });
                })
            })
        }
        return promise2;
    }
    catch(onRejected){
        if(this.status === 'rejected'){
            promise2 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        // If either onFulfilled or onRejected returns a value x,
                         // run the Promise Resolution Procedure [[Resolve]](promise2, x).
                        let x = onRejected(this.reason);
                        resolvePromsie(promise2, x, resolve, reject);
                    } catch (err) {
                        reject(err);
                    }
                }, 0)
            })
        }
    }
    

}


function resolvePromsie(promise, x, resolve, reject){
        // 規(guī)范說先promise是不是來自同一個(gè)對象,并返回一個(gè)理由
        // If promise and x refer to the same object, reject promise with a TypeError as the reason.
        try {
            // If promise and x refer to the same object, reject promise with a TypeError as the reason.
            // 如果是相同引用就拋出錯(cuò)誤
            // if(promise === x) return reject(new TypeError('不能循環(huán)引用'));
            // if x is an object or function,
            // 如果是對象瑞驱,或是函數(shù)娘摔,我們就要看then是不是函數(shù)
            if(x != null && (typeof x === 'object' || typeof x === 'function')){
                // Let then be x.then
                let then = x.then;
                if(typeof then === 'function'){
                    // If then is a function, call it with x as this,
                    // first argument resolvePromise, and second argument rejectPromise, where:
                    // 執(zhí)行then函數(shù),拿到返回值
                    then.call(x, y => {
                        resolvePromsie(promise, y, resolve, reject);
                    }, (err) => {
                        reject(err);
                    })
                }else{
                    resolve(x);
                }
            }else{
                resolve(x);
            }
        } catch (err) {
            reject(err)
        }
    }



var mypromise = new MyPromise((resolve,reject) => {
    resolve('第一個(gè)異步任務(wù) OK');
    // let timeOut = Math.random()*2;
    // setTimeout(function () {
 //        if (timeOut < 1) {
 //            resolve('第一個(gè)異步任務(wù) OK');
 //        }
 //        else {
 //            reject('第一個(gè)異步任務(wù) reject');
 //        }
 //    }, timeOut * 1000);
})
var mypromise2 = new MyPromise((resolve,reject) => {
    resolve('第二個(gè)異步任務(wù)');
})

// 測試
mypromise.then(function(data){
    log(data)
    return mypromise2;
},function(error){
    log(error)
    return mypromise2;
}).then().then().then(function(rd){
    log(rd);
   return 'test'
}).then(function(val){
    log(val);
}).then(function(val){
    log(val)
});



log('A'+111)
setTimeout(()=>{
    log('setTimeout 0ms')
})
setTimeout(()=>{
    log('setTimeout 10ms')
},10)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唤反,一起剝皮案震驚了整個(gè)濱河市验夯,隨后出現(xiàn)的幾起案子竿刁,更是在濱河造成了極大的恐慌蚯舱,老刑警劉巖随常,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拥刻,居然都是意外死亡怜瞒,警方通過查閱死者的電腦和手機(jī)父泳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門般哼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吴汪,“玉大人,你說我怎么就攤上這事蒸眠⊙龋” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵楞卡,是天一觀的道長霜运。 經(jīng)常有香客問我,道長蒋腮,這世上最難降的妖魔是什么淘捡? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮池摧,結(jié)果婚禮上焦除,老公的妹妹穿的比我還像新娘。我一直安慰自己作彤,他們只是感情好膘魄,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著竭讳,像睡著了一般创葡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绢慢,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天灿渴,我揣著相機(jī)與錄音,去河邊找鬼胰舆。 笑死逻杖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的思瘟。 我是一名探鬼主播荸百,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼滨攻!你這毒婦竟也來了够话?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤光绕,失蹤者是張志新(化名)和其女友劉穎女嘲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诞帐,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡欣尼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愕鼓。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钙态,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菇晃,到底是詐尸還是另有隱情册倒,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布磺送,位于F島的核電站驻子,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏估灿。R本人自食惡果不足惜崇呵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望馅袁。 院中可真熱鬧演熟,春花似錦、人聲如沸司顿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽大溜。三九已至化漆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钦奋,已是汗流浹背座云。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留付材,地道東北人朦拖。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像厌衔,于是被迫代替她去往敵國和親璧帝。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容

  • title: promise總結(jié) 總結(jié)在前 前言 下文類似 Promise#then富寿、Promise#resolv...
    JyLie閱讀 12,228評論 1 21
  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案睬隶,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,700評論 1 56
  • Promise對象是一種解決異步問題的方法,還有的解決方案是asyns 和 await (es7) 這么是目前的終...
    站在大神的肩膀上看世界閱讀 1,259評論 0 6
  • 00、前言Promise 是異步編程的一種解決方案变勇,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大恤左。它由社區(qū)...
    夜幕小草閱讀 2,128評論 0 12
  • Prepending(進(jìn)行時(shí)),Resolve(成功了),Reject(失敗了)飞袋,then......等 1.Pr...
    _菩提本無樹_閱讀 48,988評論 0 21