成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Promise 規(guī)范解讀及實(shí)現(xiàn)細(xì)節(jié) (一)

gougoujiang / 663人閱讀

摘要:宏任務(wù)和微任務(wù)這兩個(gè)是指兩個(gè)隊(duì)列,腳本整體代碼的回調(diào)及渲染都會(huì)被加入到隊(duì)列中回調(diào)瀏覽器實(shí)現(xiàn)回調(diào)都會(huì)被加入到隊(duì)列。

1. macrotask (宏任務(wù))和 microtask (微任務(wù))

這兩個(gè)是指兩個(gè)隊(duì)列,腳本整體代碼、setTimeout、setInterval、setImmediate、I/O、的回調(diào)及UI渲染都會(huì)被加入到 macrotask 隊(duì)列中, process.nextTick回調(diào)、Promise(瀏覽器實(shí)現(xiàn))、MutationObserver回調(diào)都會(huì)被加入到microtask隊(duì)列。

1 當(dāng)瀏覽器進(jìn)入事件循環(huán)時(shí),先去看macrotask中有沒(méi)有具備執(zhí)行條件的任務(wù)

2 如果有則選取一個(gè)(只選一個(gè))執(zhí)行

3 沒(méi)有則去看microtask隊(duì)列有沒(méi)有具備執(zhí)行條件的任務(wù)

4 有則全部執(zhí)行(全部執(zhí)行)

5 去更新頁(yè)面

6 然后重復(fù)以上行為

2. Promise 介紹

Promise主要的功能是將異步執(zhí)行結(jié)果保存起來(lái),從而使得我們不再用回調(diào)的方式去處理異步任務(wù)的結(jié)果,我們通過(guò)一個(gè)回調(diào)將異步任務(wù)的結(jié)果保存起來(lái),在以后某個(gè)時(shí)刻通過(guò)各種姿勢(shì)去使用它new romise(excutor).then(function(result)}).then(function(result){});的方式去執(zhí)行異步任務(wù),Promise 是通過(guò)回調(diào)來(lái)實(shí)現(xiàn)的,但它將回調(diào)統(tǒng)一,使得我們不在去直接接觸回調(diào),用看似有點(diǎn)像同步的方式去寫(xiě)異步任務(wù),也就僅僅是這樣而已,并沒(méi)有什么新東西,這種同步方式只能說(shuō)是類(lèi)似同步,下一篇會(huì)講寫(xiě)法更接近同步、更加有建術(shù)的 generator 。

3. Promise 的構(gòu)造函數(shù)應(yīng)該是這樣的
function Promise(excutor) {
    var self = this;
    var status = "PENDING";  //Promise的當(dāng)前狀態(tài)
    var data = undefined;  //當(dāng)前excutor(就是用戶(hù)的異步任務(wù))的執(zhí)行結(jié)果
    self.onResolvedCallback = [];  //excutor 執(zhí)行成功后回調(diào)函數(shù)隊(duì)列
    self.onRejectedCallback = [];  //excutor 執(zhí)行失敗后回調(diào)函數(shù)隊(duì)列

    function resolve(value) {  
        // TUDO 異步任務(wù)執(zhí)行成功后的行為
        // 1 改變當(dāng)前promise的status值 調(diào)用該方法 PENDING->RESOLVED
        // 2 執(zhí)行onResolvedCallback隊(duì)列里面的所有回調(diào)函數(shù)并傳遞異步任務(wù)的異步處理結(jié)果
        // onResolvedCallback[i](data)
    }

    function reject(value) {
        // TUDO 異步任務(wù)執(zhí)行失敗后的行為
        // 1 改變當(dāng)前promise的status值 調(diào)用該方法 PENDING->REJECTED
        // 2 執(zhí)行onRejectedCallback隊(duì)列里面的所有回調(diào)函數(shù)并傳遞異步任務(wù)的異步處理結(jié)果
        // onRejectedCallback[i](data)
    }

    excutor(resolve, reject);  //執(zhí)行用戶(hù)添加的任務(wù)
}

Promise.prototype.then = function (onResolved, onRejected) {
    // onResolved異步任務(wù)執(zhí)行成功的回調(diào)
    // onRejected異步任務(wù)執(zhí)行失敗后的回調(diào)
}

看起來(lái)就是這樣的 具體使用方式
new Promise(function(resolve,reject){
    setTimeout(function(result){
        // resolve(result) 或reject(result) 根據(jù)返回值決定
        //這里我們確實(shí)還是寫(xiě)了回調(diào),但是我們?cè)诨卣{(diào)里面沒(méi)有做太多的事件
        //僅僅是傳遞了異步處理結(jié)果 想想如果,我們?cè)谶@里又要做依賴(lài)于result的
        //異步任務(wù)會(huì)怎樣,回調(diào)地獄,代碼結(jié)構(gòu)混亂,不容易讀
    });
}).then(function(result){}) //這里的result是從上面的那個(gè)回調(diào)里面?zhèn)鬟f的,是同一個(gè)值
4. 具體實(shí)現(xiàn)

(1) resolve 函數(shù)和 reject 函數(shù)

function Promise(excutor) {
    var self = this;
    var status = "PENDING";  //Promise的當(dāng)前狀態(tài)
    var data = undefined;  //當(dāng)前excutor(就是用戶(hù)的異步任務(wù))的執(zhí)行結(jié)果
    self.onResolvedCallback = [];  //excutor 執(zhí)行成功后回調(diào)函數(shù)隊(duì)列
    self.onRejectedCallback = [];  //excutor 執(zhí)行失敗后回調(diào)函數(shù)隊(duì)列

    function resolve(value) {  
        // TUDO 異步任務(wù)執(zhí)行成功后的行為
        if(self.status === "PENDING") {
            self.status = "REJECTED"; // 改變當(dāng)前promise的status值 調(diào)用該方法 PENDING->RESOLVED
            self.data = value;  // 更新當(dāng)前的data
            for(var i in self.onResolvedCallback) {
                self.onResolvedCallback[i](self.data);  //執(zhí)行onResolvedCallback隊(duì)列里面的所有回調(diào)函數(shù)并傳遞異步任務(wù)的異步處理結(jié)果
            }
        }
    }

    function reject(reson) {
        // TUDO 異步任務(wù)執(zhí)行失敗后的行為
        if(self.status === "PENDING") {
            self.status = "REJECTED";
            self.data = reson;
            for(var i in self.onRejectedCallback) {
                self.onRejectedCallback[i](self.data);
            }
        }
    }
    try {
        excutor(resolve.bind(this), reject.bind(this));  //執(zhí)行用戶(hù)添加的任務(wù)
        /*這里為什么要通過(guò)通過(guò) bind 來(lái)綁定上下文呢,主要是 resolve 依賴(lài)當(dāng)
        前 promise的內(nèi)部屬性,在excutor函數(shù)體內(nèi),我們是通過(guò) resolve(data)
        或者reject(reson) 的方式來(lái)調(diào)用通過(guò)這種方式調(diào)用 在非嚴(yán)格模式
        resolve或reject的上下文是windows,在嚴(yán)格模式下是undefined*/
    } catch(e) {
        reject.bind(this)(e);  //出現(xiàn)異常則通過(guò)reject向后傳遞
    }
}

(2) then 方法的實(shí)現(xiàn)

then方法應(yīng)當(dāng)具備如下功能
(1) then方法必須返回一個(gè)Promise對(duì)象,也就是,對(duì)應(yīng)用戶(hù)添加的邏輯要進(jìn)行包裝
(2) 同一個(gè)對(duì)象可多次調(diào)用then來(lái)添加邏輯,并且會(huì)按照添加順序執(zhí)行

//例如:

var promise = new Promise(function(resolve, reject) {
    //異步操作 并且在回調(diào)中調(diào)用了 resolve或者 reject將異步處理結(jié)果傳遞出去
});
promise.then(function(data){
    //對(duì)異步結(jié)果data進(jìn)行操作
});
promise.then(function(data){
    //對(duì)異步結(jié)果data進(jìn)行操作
});
//promise是同一個(gè)對(duì)象

(3) 可以鏈?zhǔn)秸{(diào)用

//例如:
new Promise(function(resolve, reject){
    //異步操作 并且在回調(diào)中調(diào)用了 resolve或者 reject將異步處理結(jié)果傳遞出去
}).then(function(data){}).then(function(data){});

這里第一次和第二次調(diào)用then的對(duì)象是兩個(gè)不同的對(duì)象,這里要注意

[1] 如果第一個(gè)then的參數(shù)也是一個(gè)Promise那么在第二個(gè)then的中會(huì)得到第一個(gè)then的處理結(jié)果
[2] 如果第一個(gè)then的參數(shù)是一個(gè)函數(shù)并且有返回值,則在第二個(gè)then中會(huì)接收到這個(gè)返回值
[3] 其它情況下都會(huì)得到通過(guò) new Promise(fn) 這里這個(gè)異步fn的處理結(jié)果

(4) 我們寫(xiě)的Promise 要和所有符合Promise規(guī)范的 Promise 能協(xié)同工作(例如瀏覽器自帶的、第三方庫(kù)的)

/**
*@parms onResolved 任務(wù)成功時(shí)執(zhí)行的回調(diào)
*@parms onRejected 任務(wù)失敗時(shí)執(zhí)行的回調(diào)
*/
Promise.prototype.then = function(onResolved, onRejected) {
    var self = this;
    var promiseThen;  //then方法返回的promise

    //如果 onResolved或onRejected 不是函數(shù)我們忽略它,并且添加一個(gè)用于傳遞異步結(jié)果得函數(shù)
    onResolved = typeof onResolved ==="function" ? onResolved : function(value) {resolve(value);}
    onRejected = typeof onRejected ==="function" ? onRejected : function(reson) {resolve(reson);}

    /*如果在調(diào)用then添加依賴(lài)于異步處理結(jié)果的時(shí)候,異步任務(wù)已經(jīng)執(zhí)行完了,那么
    用異步的結(jié)果執(zhí)行then里面添加的任務(wù)*/
    if(self.status === "RESOLVED") {
        //這里要將then里面要添加的任務(wù)包裝成一個(gè)Promise,返回Promise 是為了(3)中的鏈?zhǔn)秸{(diào)用
        return promiseThen = new Promise(function(resolve, reject) {
            try {
                //執(zhí)行then添加的任務(wù)
                var x = onResolved(self.data);
                if(x instanceof Promise) {
                    /*如果then添加的任務(wù)有返回值,并且返回值是Promise對(duì)象
                    則讓promiseThen去接受x的狀態(tài)和data值注意,這里將
                    promiseThen的resolve,和reject作為x的then參數(shù)傳入,這
                    樣當(dāng)promiseThen的resolve和reject會(huì)在適當(dāng)?shù)臅r(shí)候被調(diào)用
                    從而使得promiseThen接受了x的狀態(tài)和data值Promise的不
                    同對(duì)象之間能實(shí)現(xiàn)相互影響,是通過(guò)將自己的resolve和
                    reject添加到其它對(duì)象中*/
                    x.then(resolve, reject); 
                }
                else resolve(x); //如果x不是Promise使用x的值作為promiseThen的結(jié)果
            } catch (e) {
                reject(e);
            }
        });
    }

    //和上面邏輯相同
    if(self.status === "REJECTED") {
        return promiseThen = new Promise(function(resolve, reject){
            try {
                var x = onRejected(self.data);
                if(x instanceof Promise){
                    x.then(resolve, reject);
                }
            }catch(e) {
                reject(e);
            }
        });
    }

    if(self.status === "PENDING") {
        //當(dāng)前Promise的異步任務(wù)沒(méi)有執(zhí)行完,則將then里面的異步任務(wù) 包裝后放入隊(duì)列
        //包裝方法和上面一樣,區(qū)別是上面立即執(zhí)行,這里放入回調(diào)隊(duì)列。
        return promiseThne = new Promise(function() {
            self.onResolvedCallback.push(function(){
                try {
                    var x = onResolved(self.data);
                    if(x instanceof Promise) {
                        x.then(resolve, reject);
                    } catch(e) {
                        reject(e);
                    }
                }
            });

            self.onRejectedCallback.push(function(){
                try {
                    var x = onRejected(self.data);
                    if(x instanceof Promise) {
                        x.then(resolve, reject);
                    } catch(e) {
                        reject(e);
                    }
                } 
            });
        });
    }

}

寫(xiě)到這里Promise具體實(shí)現(xiàn)的 (1)、(2)、(3)的功能已經(jīng)完成了,也就是如果不考慮與其它
的Promise交互那么Promise的原理已經(jīng)說(shuō)清楚了,本來(lái)打算一篇文章寫(xiě)完,但是篇幅太
長(zhǎng),所以打算分兩篇文章來(lái)寫(xiě),下一篇是generator,之后我會(huì)按照規(guī)范將(4)部分實(shí)現(xiàn)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/83919.html

相關(guān)文章

  • Promise 規(guī)范解讀實(shí)現(xiàn)細(xì)節(jié) (二)

    摘要:開(kāi)始前的實(shí)現(xiàn)原理已經(jīng)在規(guī)范解讀及實(shí)現(xiàn)細(xì)節(jié)一中說(shuō)的很清楚了,這里將詳細(xì)分析規(guī)范中的解析過(guò)程,最后會(huì)實(shí)現(xiàn)一個(gè)并提供用于測(cè)試的代碼方法分析這里的調(diào)用會(huì)產(chǎn)生一個(gè)新的不同實(shí)例對(duì)于上一級(jí)的終值會(huì)作為的參數(shù)被傳入對(duì)于如果返回一個(gè)返回一個(gè)那么的狀態(tài)和值由決 開(kāi)始前 Promise的實(shí)現(xiàn)原理已經(jīng)在 Promise 規(guī)范解讀及實(shí)現(xiàn)細(xì)節(jié) (一) 中說(shuō)的很清楚了,這里將詳細(xì)分析 Promises/A+規(guī)范 中...

    Michael_Lin 評(píng)論0 收藏0
  • 理解 Promise 的工作原理

    摘要:前兩個(gè)函數(shù)對(duì)應(yīng)的兩種狀態(tài)和的回調(diào)函數(shù)。返回值是和對(duì)應(yīng)的方法,但是會(huì)在下一事件循環(huán)返回。此外,在規(guī)范中,由方法生成的對(duì)象是已執(zhí)行還是已拒絕,取決于由方法調(diào)用的那個(gè)回調(diào)是返回值還是拋出錯(cuò)誤。但是對(duì)于其工作原理卻有些懵懂和好奇。 原文: https://blog.coding.net/blog/how-do-promises-work Javascript 采用回調(diào)函數(shù)(callback)來(lái)...

    Achilles 評(píng)論0 收藏0
  • Promises A+規(guī)范原文解讀 + es6實(shí)現(xiàn)(附詳細(xì)注釋?zhuān)?/b>

    摘要:英文官方文檔原文前言寫(xiě)本文的目的,是為了更好的理解,通過(guò)解讀翻譯原文,逐行解析原文通過(guò)代碼一行一行實(shí)現(xiàn)。英中原因是一個(gè)值結(jié)果表明被拒絕的原因。英中在法律允許的范圍內(nèi),組織已放棄所有版權(quán)及規(guī)范的相關(guān)或相鄰權(quán)利。 英文官方文檔原文:https://promisesaplus.com/ 前言 寫(xiě)本文的目的,是為了更好的理解promise,通過(guò)解讀翻譯原文,逐行解析原文通過(guò)代碼一行一行實(shí)現(xiàn)。...

    v1 評(píng)論0 收藏0
  • 超詳細(xì)的webpack原理解讀

    摘要:生成文件,是模塊構(gòu)建的終點(diǎn),包括輸出文件與輸出路徑。這里配置了處理各模塊的,包括預(yù)處理,編譯,圖片處理。各插件對(duì)象,在的事件流中執(zhí)行對(duì)應(yīng)的方法。修改改成引入模塊在目錄下執(zhí)行, webpack原理解讀 本文抄自《深入淺出webpack》,建議想學(xué)習(xí)原理的手打一遍,操作一遍,給別人講一遍,然后就會(huì)了在閱讀前希望您已有webpack相關(guān)的實(shí)踐經(jīng)驗(yàn),不然讀了也讀不懂 本文閱讀需要幾分鐘,理解需...

    wenhai.he 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確的學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類(lèi)中文書(shū)籍收錄并推薦地址,以后在倉(cāng)庫(kù)里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來(lái)越多的科技公司和開(kāi)發(fā)者開(kāi)始使用開(kāi)發(fā)各種應(yīng)用。 說(shuō)明 2017-12-14 我發(fā)了一篇文章《沒(méi)用過(guò)Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車(chē)的還坐過(guò)站了。大家可以很...

    Edison 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<