国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

ES6(一) —— 異步編程解決辦法[從回調(diào)函數(shù)到promise,generator,async]

greatwhole / 908人閱讀

摘要:回調(diào)函數(shù)這是最原始的一種異步解決方法。從的對象演化而來對象是提出的一種對異步編程的解決方案,但它不是新的語法,而是一種新的寫法,允許將回調(diào)函數(shù)的嵌套改成鏈?zhǔn)秸{(diào)用。

一、前言

異步編程對JavaScript來說非常重要,因?yàn)镴avaScript的語言環(huán)境是單線程的,如果沒有異步編程將變得非常可怕,估計(jì)根本無法使用。這篇文章就來總結(jié)一下從最原始的回調(diào)函數(shù)到現(xiàn)在的ES6、ES7的新方法。

文章并不會具體介紹每種方法的原理,如果不是特別懂需要詳細(xì)了解的同學(xué)可以看阮一峰的ES6入門。阮大大介紹得非常具體,從原理到用法。

- 什么是單線程?

單線程就是指進(jìn)程中只有一個(gè)線程。單線程執(zhí)行程序時(shí),按照代碼的順序,上一個(gè)任務(wù)完成后才會執(zhí)行下一個(gè)任務(wù)。同一個(gè)時(shí)間只做一件事情。

- 為什么JavaScript是單線程的?

JavaScript的主要作用就是操作DOM,如果兩段JS同時(shí)操作一個(gè)DOM,會引起渲染的沖突。所以JavaScript只能是單線程的。
HTML5中提出的Web Worker,允許JavaScript腳本創(chuàng)建多個(gè)線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個(gè)新標(biāo)準(zhǔn)并沒有改變JavaScript單線程的本質(zhì)。

- 什么是異步?

同步是指任務(wù)一件一件的按順序完成,上一件沒有完成就無法做下一件;而異步則是指,開始做一件事之后就放在那兒等待結(jié)果,不需要守著,繼續(xù)做下一件事即可。

異步可以解決JavaScript單線程效率低、同一事件只能做一件事情的問題。

console.log(1);
setTimeOut(()=>{
    console.log(2);
},1000)
console.log(3);

這段代碼首先會打印1,然后打印3,過1000ms以后打印2。

然而這段代碼內(nèi)部是如何運(yùn)行的呢,打印1和打印3的命令是同步命令,所以直接按順序放到主進(jìn)程中執(zhí)行,setTimeOut里的是一個(gè)異步命令,在1000ms以后會被放入異步隊(duì)列中。而主進(jìn)程會通過事件循環(huán)(event loop)不斷地從異步隊(duì)列中取出命令,然后執(zhí)行。當(dāng)主進(jìn)程在1000ms以后查詢到了打印2的命令時(shí),便把這個(gè)函數(shù)拿到主進(jìn)程中執(zhí)行。

二、異步編程的解決辦法

這里全部用ajax連續(xù)調(diào)用例子,接口是豆瓣的真實(shí)接口,可以得到具體的數(shù)據(jù),但有限制每小時(shí)150次。

1.回調(diào)函數(shù)

這是最原始的一種異步解決方法。回調(diào)函數(shù),就是指一件事做完以后,拿到結(jié)果后要做的事情。

var urlBase = "https://api.douban.com/";
var start = 0,count = 5;
$.ajax({
    url: urlBase+"v2/book/user/1219073/collections",
    type: "GET",
    dataType: "jsonp",
    data:{
        start:start,
        count:count
    },
    success: function(data){
        console.log(data);
        start+=count;
        $.ajax({
            url: urlBase+"v2/book/user/1219073/collections",
            type: "GET",
            dataType: "jsonp",
            data:{
                start:start,
                count:count
            },
            success:function(data){
                console.log(data);
                start+=count;
                $.ajax({
                    url: urlBase+"v2/book/user/1219073/collections",
                    type: "GET",
                    dataType: "jsonp",
                    data:{
                        start:start,
                        count:count
                    },
                    success:function(data){
                        console.log(data);
                    }
                })
            }
        })
    }
})

這是用jquery的ajax方法調(diào)用的豆瓣某個(gè)人的收藏的圖書,start和count是豆瓣提供的接口參數(shù),start代表從哪一條數(shù)據(jù)開始獲取,count代表一共獲取多少條數(shù)據(jù)。

從上面的代碼可以看到多個(gè)回調(diào)函數(shù)的嵌套,如果需要調(diào)用得越多,回調(diào)也堆積得越多,多了以后代碼就很難維護(hù),時(shí)間久了自己也要花很久才能看懂代碼。

改進(jìn)辦法

將每一次回調(diào)的方法封裝成函數(shù),代碼量會減少很多。

var urlBase = "https://api.douban.com/";
var start = 0,count = 5;
function ajax(start,count,cb){
    $.ajax({
        url: urlBase+"v2/book/user/1219073/collections",
        type: "GET",
        dataType: "jsonp",
        data:{
            start:start,
            count:count
        },
        success:function(data){
            console.log(data);
            start+=count;
            cb && cb(start);
        }
    })

}

ajax(start,count,function(start){
    ajax(start,count,function(start){
        ajax(start,count)
    })
});

但是這樣依然沒有解決“回調(diào)地獄”的問題,當(dāng)每次回調(diào)的邏輯操作變得越來越多的時(shí)候,代碼依然難以維護(hù)。

2.Promise(從jQuery的deferred對象演化而來)

Promise對象是ES6提出的一種對異步編程的解決方案,但它不是新的語法,而是一種新的寫法,允許將回調(diào)函數(shù)的嵌套改成鏈?zhǔn)秸{(diào)用。

雖然說Promise是ES6提出的標(biāo)準(zhǔn),但其實(shí)jQuery在1.5版本以后就提出了類似的東西,叫做deferred對象。具體學(xué)習(xí)可以看jQuery的deferred對象詳解。

const urlBase = "https://api.douban.com/";
let start = 0,count = 5;
function ajax(start,count){
    let dtd = $.Deferred();
    
    $.ajax({
        url: urlBase+"v2/book/user/1219073/collections",
        type: "GET",
        dataType: "jsonp",
        data:{
            start:start,
            count:count
        },
        success:function(data){
            start+=count;
            dtd.resolve(data,start);
        },
        error:function(err){
            dtd.reject(err);
        }
    })

    return dtd;
}


ajax(start,count).then((data1,start) => {
    console.log(data1);
    return ajax(start,count);
}).then((data2,start) => {
    console.log(data2);
    return ajax(start,count);
}).then((data3,start) => {
    console.log(data3);
}).catch((err) => {
    console.log("這里出錯(cuò)啦");
})

從這段代碼可以看出來,寫法和promise非常相似了,可以猜測promise就是從deferred演化而來的。

同樣的功能實(shí)現(xiàn)可以改成以下寫法:

const urlBase = "https://api.douban.com/";
let start = 0,count = 5;
function ajax(start,count){
    return new Promise(function(resolve,reject){
        $.ajax({
            url: urlBase+"v2/book/user/1219073/collections",
            type: "GET",
            dataType: "jsonp",
            data:{
                start:start,
                count:count
            },
            success:function(data){
                start+=count;
                resolve(data,start);
            },
            error:function(err){
                reject(err);
            }
        })
    })
}


ajax(start,count).then((data1,start) => {
    console.log(data1);
    return ajax(start,count);
}).then((data2,start) => {
    console.log(data2);
    return ajax(start,count);
}).then((data3,start) => {
    console.log(data3);
}).catch((err) => {
    console.log("這里出錯(cuò)啦");
})

Promise使用.then方法解決了回調(diào)的問題,但代碼依然冗余,且語義不強(qiáng),放眼望去全是.then方法,很難找出需要修改的地方。

3.Generator

Generator函數(shù)也是ES6中提出的異步編程解決方法,整個(gè) Generator 函數(shù)就是一個(gè)封裝的異步任務(wù),或者說是異步任務(wù)的容器。最大特點(diǎn)就是可以交出函數(shù)的執(zhí)行權(quán)(即暫停執(zhí)行)。
異步操作需要暫停的地方,都用yield語句注明。

const urlBase = "https://api.douban.com/";
let start = 0,count = 5;
function ajax(start,count){
    return new Promise(function(resolve,reject){
        $.ajax({
            url: urlBase+"v2/book/user/1219073/collections",
            type: "GET",
            dataType: "jsonp",
            data:{
                start:start,
                count:count
            },
            success:function(data){
                start+=count;
                resolve(data);
            },
            error:function(err){
                reject(err);
            }
        })
    })
    
}

let gen = function*(){
    yield ajax(start,count);
    start+=count;
    yield ajax(start,count);
    start+=count;
    yield ajax(start,count);
}


let g = gen();
g.next().value.then((data1) => {
    console.log(data1);
    g.next().value.then((data2) => {
        console.log(data2);
        g.next().value.then((data3) => {
            console.log(data3);
        })
    })
})

這樣在gen函數(shù)內(nèi)三個(gè)ajax請求就看起來非常像同步的寫法了,但是執(zhí)行的過程并不清晰,且需要手動(dòng).next來執(zhí)行下一個(gè)操作。這并不是我們想要的完美異步方案。

4.async

async函數(shù)是ES7提出的一種異步解決方案,它與generator并無大的不同,而且可以說它就是generator的一種語法糖。它的語法只是把generator函數(shù)里的*換成了async,yield換成了await,但它同時(shí)有幾個(gè)優(yōu)點(diǎn)。

(1)內(nèi)置執(zhí)行器。這表示它不需要不停的next來使程序繼續(xù)向下進(jìn)行。
(2)更好的語義。async代表異步,await代表等待。
(3)更廣的適用性。await命令后面可以跟Promise對象,也可以是原始類型的值。
(4)返回的是Promise。

const urlBase = "https://api.douban.com/";
let start = 0,count = 5;
function ajax(start,count){
    return new Promise(function(resolve,reject){
        $.ajax({
            url: urlBase+"v2/book/user/1219073/collections",
            type: "GET",
            dataType: "jsonp",
            data:{
                start:start,
                count:count
            },
            success:function(data){
                start+=count;
                resolve(data);
            },
            error:function(err){
                reject(err);
            }
        })
    })
    
}

async function getData(){
    let data = null;
    try{
        for(let i = 0;i < 3;i++){
            data = await ajax(start,count);
            console.log(data);
            start+=count;
        }
    }
    catch(err){
        console.log(err);
    }
}

getData();

用async函數(shù)改寫之后語義清晰,代碼量也減少了,并且內(nèi)部自帶執(zhí)行器,感覺很符合想象中的異步解決方法。

三、結(jié)語

到此就把幾種常見的異步回調(diào)方法介紹完了,我個(gè)人感覺用async+promise是最好的辦法。當(dāng)然為了更加深刻的理解這些異步解決辦法,一定要多多的用到項(xiàng)目中,多用才會多理解。

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

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/93361.html

相關(guān)文章

  • JavaScript異步編程的終極演變

    摘要:在誕生以前,異步編程的方式大概有下面四種回調(diào)函數(shù)事件監(jiān)聽發(fā)布訂閱對象將異步編程帶入了一個(gè)全新的階段,中的函數(shù)更是給出了異步編程的終極解決方案。這意味著,出錯(cuò)的代碼與處理錯(cuò)誤的代碼,實(shí)現(xiàn)了時(shí)間和空間上的分離,這對于異步編程無疑是很重要的。 寫在前面 有一個(gè)有趣的問題: 為什么Node.js約定回調(diào)函數(shù)的第一個(gè)參數(shù)必須是錯(cuò)誤對象err(如果沒有錯(cuò)誤,該參數(shù)就是null)? 原因是執(zhí)行回調(diào)函...

    whjin 評論0 收藏0
  • ES6-7

    摘要:的翻譯文檔由的維護(hù)很多人說,阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評論0 收藏0
  • ES6中的異步編程Generators函數(shù)+Promise:最強(qiáng)大的異步處理方式

    摘要:更好的異步編程上面的方法可以適用于那些比較簡單的異步工作流程。小結(jié)的組合目前是最強(qiáng)大,也是最優(yōu)雅的異步流程管理編程方式。 訪問原文地址 generators主要作用就是提供了一種,單線程的,很像同步方法的編程風(fēng)格,方便你把異步實(shí)現(xiàn)的那些細(xì)節(jié)藏在別處。這讓我們可以用一種很自然的方式書寫我們代碼中的流程和狀態(tài)邏輯,不再需要去遵循那些奇怪的異步編程風(fēng)格。 換句話說,通過將我們generato...

    Taonce 評論0 收藏0
  • 篇文章了解前端異步編程方案演變

    摘要:對于而言,異步編程我們可以采用回調(diào)函數(shù),事件監(jiān)聽,發(fā)布訂閱等方案,在之后,又新添了,,的方案。總結(jié)本文闡述了從回調(diào)函數(shù)到的演變歷史。參考文檔深入掌握異步編程系列理解的 對于JS而言,異步編程我們可以采用回調(diào)函數(shù),事件監(jiān)聽,發(fā)布訂閱等方案,在ES6之后,又新添了Promise,Genertor,Async/Await的方案。本文將闡述從回調(diào)函數(shù)到Async/Await的演變歷史,以及它們...

    lmxdawn 評論0 收藏0
  • 細(xì)說JS異步發(fā)展歷程

    摘要:參考文章珠峰架構(gòu)課墻裂推薦細(xì)說異步函數(shù)發(fā)展歷程異步編程謝謝各位小伙伴愿意花費(fèi)寶貴的時(shí)間閱讀本文,如果本文給了您一點(diǎn)幫助或者是啟發(fā),請不要吝嗇你的贊和,您的肯定是我前進(jìn)的最大動(dòng)力。 知其然知其所以然,首先了解三個(gè)概念: 1.什么是同步? 所謂同步,就是在發(fā)出一個(gè)調(diào)用時(shí),在沒有得到結(jié)果之前,該調(diào)用就不返回。但是一旦調(diào)用返回,就得到返回值了。換句話說,就是由調(diào)用者主動(dòng)等待這個(gè)調(diào)用的結(jié)果。此調(diào)...

    RiverLi 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<