多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當前位置:首頁 > 互聯(lián)網(wǎng) > JavaScript Promise啟示錄

JavaScript Promise啟示錄

來源:程序員人生   發(fā)布時間:2014-09-14 23:51:26 閱讀次數(shù):4047次

【編者按】JavaScript是一種基于對象和事件驅(qū)動并具有相對安全性的客戶端腳本語言。自推出后就大受開發(fā)者的青睞,基于JavaScript的開發(fā)工具也不計其數(shù),開發(fā)者們可以靈活選擇,輕松構(gòu)建應(yīng)用。原文作者TAT.dmyang就JavaScript中的Promise規(guī)范給出了一些見解,目前高級瀏覽器如Chrome、Firefox都已經(jīng)內(nèi)置了Promise對象,提供更多的操作接口,如此優(yōu)雅的Promise具備哪些特性呢?且看下文:


一直以來,JavaScript處理異步都是以callback的方式,在前端開發(fā)領(lǐng)域callback機制幾乎深入人心。在設(shè)計API的時候,不管是瀏覽器廠商還是SDK開發(fā)商亦或是各種類庫的作者,基本上都已經(jīng)遵循著callback的套路。

近幾年隨著JavaScript開發(fā)模式的逐漸成熟,CommonJS規(guī)范順勢而生,其中就包括提出了Promise規(guī)范,Promise完全改變了js異步編程的寫法,讓異步編程變得十分的易于理解。

在callback的模型里邊,我們假設(shè)需要執(zhí)行一個異步隊列,代碼看起來可能像這樣:

loadImg('a.jpg', function() {
    loadImg('b.jpg', function() {
        loadImg('c.jpg', function() {
            console.log('all done!');
        });
    });
});

這也就是我們常說的回調(diào)金字塔,當異步的任務(wù)很多的時候,維護大量的callback將是一場災(zāi)難。當今Node.js大熱,好像很多團隊都要用它來做點東西以沾沾“洋氣”,曾經(jīng)跟一個運維的同學聊天,他們也是打算使用Node.js做一些事情,可是一想到j(luò)s的層層回調(diào)就望而卻步。

好,扯淡完畢,下面進入正題。

Promise可能大家都不陌生,因為Promise規(guī)范已經(jīng)出來好一段時間了,同時Promise也已經(jīng)納入了ES6,而且高版本的chrome、firefox瀏覽器都已經(jīng)原生實現(xiàn)了Promise,只不過和現(xiàn)如今流行的類Promise類庫相比少些API。

所謂Promise,字面上可以理解為“承諾”,就是說A調(diào)用B,B返回一個“承諾”給A,然后A就可以在寫計劃的時候這么寫:當B返回結(jié)果給我的時候,A執(zhí)行方案S1,反之如果B因為什么原因沒有給到A想要的結(jié)果,那么A執(zhí)行應(yīng)急方案S2,這樣一來,所有的潛在風險都在A的可控范圍之內(nèi)了。

上面這句話,翻譯成代碼類似:

var resB = B();
var runA = function() {
    resB.then(execS1, execS2);
};
runA();

只看上面這行代碼,好像看不出什么特別之處。但現(xiàn)實情況可能比這個復雜許多,A要完成一件事,可能要依賴不止B一個人的響應(yīng),可能需要同時向多個人詢問,當收到所有的應(yīng)答之后再執(zhí)行下一步的方案。最終翻譯成代碼可能像這樣:

var resB = B();
var resC = C();
...

var runA = function() {
    reqB
        .then(resC, execS2)
        .then(resD, execS3)
        .then(resE, execS4)
        ...
        .then(execS1);
};

runA();

在這里,當每一個被詢問者做出不符合預期的應(yīng)答時都用了不同的處理機制。事實上,Promise規(guī)范沒有要求這樣做,你甚至可以不做任何的處理(即不傳入then的第二個參數(shù))或者統(tǒng)一處理。

好了,下面我們來認識下Promise/A+規(guī)范:

可以看到,Promise規(guī)范的內(nèi)容并不算多,大家可以試著自己實現(xiàn)以下Promise。

以下是筆者自己在參考許多類Promise庫之后簡單實現(xiàn)的一個Promise,代碼請移步promiseA。

簡單分析下思路:

構(gòu)造函數(shù)Promise接受一個函數(shù)resolver,可以理解為傳入一個異步任務(wù),resolver接受兩個參數(shù),一個是成功時的回調(diào),一個是失敗時的回調(diào),這兩參數(shù)和通過then傳入的參數(shù)是對等的。

其次是then的實現(xiàn),由于Promise要求then必須返回一個promise,所以在then調(diào)用的時候會新生成一個promise,掛在當前promise的_next上,同一個promise多次調(diào)用都只會返回之前生成的_next

由于then方法接受的兩個參數(shù)都是可選的,而且類型也沒限制,可以是函數(shù),也可以是一個具體的值,還可以是另一個promise。下面是then的具體實現(xiàn):

Promise.prototype.then = function(resolve, reject) {
    var next = this._next || (this._next = Promise());
    var status = this.status;
    var x;

    if('pending' === status) {
        isFn(resolve) && this._resolves.push(resolve);
        isFn(reject) && this._rejects.push(reject);
        return next;
    }

    if('resolved' === status) {
        if(!isFn(resolve)) {
            next.resolve(resolve);
        } else {
            try {
                x = resolve(this.value);
                resolveX(next, x);
            } catch(e) {
                this.reject(e);
            }
        }
        return next;
    }

    if('rejected' === status) {
        if(!isFn(reject)) {
            next.reject(reject);
        } else {
            try {
                x = reject(this.reason);
                resolveX(next, x);
            } catch(e) {
                this.reject(e);
            }
        }
        return next;
    }
};

這里,then做了簡化,其他promise類庫的實現(xiàn)比這個要復雜得多,同時功能也更多,比如還有第三個參數(shù)――notify,表示promise當前的進度,這在設(shè)計文件上傳等時很有用。對then的各種參數(shù)的處理是最復雜的部分,有興趣的同學可以參看其他類Promise庫的實現(xiàn)。

在then的基礎(chǔ)上,應(yīng)該還需要至少兩個方法,分別是完成promise的狀態(tài)從pending到resolved或rejected的轉(zhuǎn)換,同時執(zhí)行相應(yīng)的回調(diào)隊列,即resolve()reject()方法。

到此,一個簡單的promise就設(shè)計完成了,下面簡單實現(xiàn)下兩個promise化的函數(shù):

function sleep(ms) {
    return function(v) {
        var p = Promise();

        setTimeout(function() {
            p.resolve(v);
        });

        return p;
    };
};

function getImg(url) {
    var p = Promise();
    var img = new Image();

    img.onload = function() {
        p.resolve(this);
    };

    img.onerror = function(err) {
        p.reject(err);
    };

    img.url = url;

    return p;
};

由于Promise構(gòu)造函數(shù)接受一個異步任務(wù)作為參數(shù),所以getImg還可以這樣調(diào)用:

function getImg(url) {
    return Promise(function(resolve, reject) {
        var img = new Image();

        img.onload = function() {
            resolve(this);
        };

        img.onerror = function(err) {
            reject(err);
        };

        img.url = url;
    });
};

接下來(見證奇跡的時刻),假設(shè)有一個BT的需求要這么實現(xiàn):異步獲取一個json配置,解析json數(shù)據(jù)拿到里邊的圖片,然后按順序隊列加載圖片,沒張圖片加載時給個loading效果

function addImg(img) {
    $('#list').find('> li:last-child').html('').append(img);
};

function prepend() {
    $('<li>')
        .html('loading...')
        .appendTo($('#list'));
};

function run() {
    $('#done').hide();
    getData('map.json')
        .then(function(data) {
            $('h4').html(data.name);

            return data.list.reduce(function(promise, item) {
                return promise
                    .then(prepend)
                    .then(sleep(1000))
                    .then(function() {
                        return getImg(item.url);
                    })
                    .then(addImg);
            }, Promise.resolve());
        })
        .then(sleep(300))
        .then(function() {
            $('#done').show();
        });
};

$('#run').on('click', run);

這里的sleep只是為了看效果加的,可猛擊查看demo!當然,Node.js的例子可查看這里。

在這里,Promise.resolve(v)靜態(tài)方法只是簡單返回一個以v為肯定結(jié)果的promise,v可不傳入,也可以是一個函數(shù)或者是一個包含then方法的對象或函數(shù)(即thenable)。

類似的靜態(tài)方法還有Promise.cast(promise),生成一個以promise為肯定結(jié)果的promise;

Promise.reject(reason),生成一個以reason為否定結(jié)果的promise。

我們實際的使用場景可能很復雜,往往需要多個異步的任務(wù)穿插執(zhí)行,并行或者串行同在。這時候,可以對Promise進行各種擴展,比如實現(xiàn)Promise.all(),接受promises隊列并等待他們完成再繼續(xù),再比如Promise.any(),promises隊列中有任何一個處于完成態(tài)時即觸發(fā)下一步操作。

標準的Promise

可參考html5rocks的這篇文章JavaScript Promises,目前高級瀏覽器如Chrome、Firefox都已經(jīng)內(nèi)置了Promise對象,提供更多的操作接口,比如Promise.all(),支持傳入一個promises數(shù)組,當所有promises都完成時執(zhí)行then,還有就是更加友好強大的異常捕獲,應(yīng)對日常的異步編程,應(yīng)該足夠了。

第三方庫的Promise

現(xiàn)今流行的各大js庫,幾乎都不同程度的實現(xiàn)了Promise,如dojo,jQuery、Zepto、when.js、Q等,只是暴露出來的大都是Deferred對象,以jQuery(Zepto類似)為例,實現(xiàn)上面的getImg()

function getImg(url) {
    var def = $.Deferred();
    var img = new Image();

    img.onload = function() {
        def.resolve(this);
    };

    img.onerror = function(err) {
        def.reject(err);
    };

    img.src = url;

    return def.promise();
};

當然,jQuery中,很多的操作都返回的是Deferred或promise,如animateajax

// animate
$('.box')
    .animate({'opacity': 0}, 1000)
    .promise()
    .then(function() {
        console.log('done');
    });

// ajax
$.ajax(options).then(success, fail);
$.ajax(options).done(success).fail(fail);

// ajax queue
$.when($.ajax(options1), $.ajax(options2))
    .then(function() {
        console.log('all done.');
    }, function() {
        console.error('There something wrong.');
    });

jQuery還實現(xiàn)了done()fail()方法,其實都是then方法的shortcut。

處理promises隊列,jQuery實現(xiàn)的是$.when()方法,用法和Promise.all()類似。

其他類庫,這里值得一提的是when.js,本身代碼不多,完整實現(xiàn)Promise,同時支持browser和Node.js,而且提供更加豐富的API,是個不錯的選擇。這里限于篇幅,不再展開。

尾聲

我們看到,不管Promise實現(xiàn)怎么復雜,但是它的用法卻很簡單,組織的代碼很清晰,從此不用再受callback的折磨了。

最后,Promise是如此的優(yōu)雅!但Promise也只是解決了回調(diào)的深層嵌套的問題,真正簡化JavaScript異步編程的還是Generator,在Node.js端,建議考慮Generator。

參考文獻

  • JavaScript Promises
  • JavaScript Promises(中文)
  • when.js
  • Asynch JS: The Power Of $.Deferred
  • jQuery: $.Deferred()
原文出自:Alloyteam

(責編/夏夢竹)
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 性欧美bb| 老司机福利在线免费观看 | 欧美日韩成人高清在线播放 | 91久久澡人人爽人人添 | 欧美性18 | 国产h在线观看 | 国内一区二区三区精品视频 | 国产高清在线精品一区在线 | 国产欧美第一页 | 亚洲国产国产综合一区首页 | 美女视频在线观看网站 | 色婷婷久久综合中文久久蜜桃 | xxxx性xxxx| 亚洲免费黄色片 | 国产第一福利 | 亚洲国产专区 | 亚洲国产精品久久日 | 久久国产精品老女人 | 日韩欧美一区二区不卡看片 | 亚洲精品永久免费 | 欧美成人性色 | 伊人久久大香线焦在观看 | 视频精品一区 | 亚洲精品456在线播放 | 久久综合九色综合桃花 | 欧美日本在线视频 | 久久久欧美综合久久久久 | 国产亚洲精品免费 | 国产精品久久久久乳精品爆 | 亚洲国产国产综合一区首页 | 老司机亚洲精品影院在线 | 成人国产在线看不卡 | 亚洲码欧美码一区二区三区 | 日韩一级欧美一级 | 日本免费乱人伦在线观看 | 精品国产综合成人亚洲区 | 国产亚洲高清在线精品不卡 | 一级日韩 | 亚洲欧美视频在线观看 | 美女的隐私视频网站蜜桃视频 | 五月天开心中文字幕 |