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

資訊專欄INFORMATION COLUMN

JavaScript 異步機(jī)制及應(yīng)用 入門教程

BoYang / 3674人閱讀

摘要:異步與同步技術(shù)研究概念介紹異步簡寫同步簡寫用比方來比喻異步就是個(gè)人同時(shí)起跑起點(diǎn)和出發(fā)時(shí)間相同在起跑時(shí)不去關(guān)心其他人會(huì)啥時(shí)候跑完尼瑪這不廢話嗎大家都才起跑怎么知道別人多就跑完同步就是個(gè)人接力跑起點(diǎn)和出發(fā)時(shí)間不同且后一個(gè)人會(huì)等待前一個(gè)人跑完才能

1. 異步與同步 技術(shù)研究 (1). 概念介紹

異步: asynchronous 簡寫async
同步: synchronous 簡寫sync

用比方來比喻
異步就是: N個(gè)人同時(shí)起跑, 起點(diǎn)和出發(fā)時(shí)間相同, 在起跑時(shí)不去關(guān)心其他人會(huì)啥時(shí)候跑完~尼瑪這不廢話嗎?大家都才起跑怎么知道別人多就跑完.
同步就是: N個(gè)人接力跑, 起點(diǎn)和出發(fā)時(shí)間不同, 且后一個(gè)人會(huì)等待前一個(gè)人跑完才能繼續(xù)跑, 也就是要關(guān)心前一個(gè)人的結(jié)果(上一行代碼的返回值).

(2). JS里面的異步/同步

JS運(yùn)行場(chǎng)景多數(shù)是在用戶瀏覽器上, 程序效率優(yōu)劣會(huì)直接影響用戶的體驗(yàn)交互. 比如一個(gè)網(wǎng)站, 在用戶注冊(cè)時(shí), 會(huì)ajax校驗(yàn)輸入再發(fā)提交表單, 如果用同步就可能會(huì)一直卡著等待ajax響應(yīng), 好幾秒結(jié)束后再跳到注冊(cè)結(jié)果頁, 這個(gè)體驗(yàn)將是非常糟糕的.

說到JS的異步, 不得不提及一個(gè)非常有代表意義函數(shù)了.

JavaScriptvar url = "/action/";
var data = "i=1";
xmlHTTP = new XMLHttpRequest();
xmlHTTP.nonce = nonce;
xmlHTTP.open("POST", url);
xmlHTTP.onreadystatechange = function(a) {
    if(a.target.readyState!=4)return false;
    try{
        console.log(a.target.responseText)
    }catch(e){
        return false;
    }
};
xmlHTTP.send(data);

或者在jQuery寫作:

JavaScript$.ajax({
    url: "/action/",
    type: "POST",
    data: "i=1",
    success: function(responseText){
        console.log(responseText);
    }
})

上面的無論是xmlHTTP.onreadystatechange, 還是success, 在JavaScript中均稱為回調(diào)方法,
以原生JS的XMLHttpRequest為例, xmlHTTP變量是個(gè)XMLHttpRequest對(duì)象, 他的onreadystatechange是在每次請(qǐng)求響應(yīng)狀態(tài)發(fā)生變化時(shí)會(huì)觸發(fā)的一個(gè)函數(shù)/方法, 然后在發(fā)出請(qǐng)求xmlHTTP.send(data)的時(shí)候, JS并不會(huì)理會(huì)onreadystatechange方法, 而當(dāng)改送請(qǐng)求到達(dá)服務(wù)器, 開始響應(yīng)或者響應(yīng)狀態(tài)改變時(shí)會(huì)調(diào)用onreadystatechange方法:

也就是
1) 請(qǐng)求發(fā)出
2) 服務(wù)器開始響應(yīng)數(shù)據(jù)
3) 執(zhí)行回調(diào)方法, 可能執(zhí)行多次

以jQuery版為例, $.ajax本身是個(gè)函數(shù), 唯一一個(gè)參數(shù)是{...} 這個(gè)對(duì)象, 然后回調(diào)方法success是作為這個(gè)對(duì)象的一個(gè)屬性傳入$.ajax的.
$.ajax()先將數(shù)據(jù)post到"/action/", 返回結(jié)果后再調(diào)用success(如果發(fā)生錯(cuò)誤會(huì)調(diào)用error).
也就是

 1) 請(qǐng)求發(fā)出
 2) 服務(wù)器開始響應(yīng)數(shù)據(jù)
 3) 響應(yīng)結(jié)束執(zhí)行回調(diào)方法

然后作為函數(shù)$.ajax, 是函數(shù)就應(yīng)該有返回值(哪怕沒有return也會(huì)返回undefined), 他本身的返回值是多少呢?
分為async:trueasync:false兩個(gè)版本:

async:true版本:

JavaScript$.ajax({"url":"a.html", type:"GET", async:true})
> Object {readyState: 1}

async:false版本:

JavaScript$.ajax({"url":"robots.txt", type:"GET", false})
> Object {readyState: 4, responseText: "

我們可以直接看到, async:true異步模式下, jquery/javascript未將結(jié)果返回... 而async:false就將結(jié)果返回了.

然后問題就來了, 為什么async:true未返回結(jié)果呢?
答案很簡單:
因?yàn)樵诜祷氐臅r(shí)候, 程序不可能知道結(jié)果. 異步就是指不用等此操作執(zhí)行出結(jié)果再往下執(zhí)行, 也就是返回的值中未包含結(jié)果.

留下一個(gè)問題, 我們是不是為了程序流程的簡單化而使用同步呢?

(3). 異步的困惑

先帖一段代碼:
a.php

php

page.js

JavaScriptfor( i = 1; i <= 4; i++ ){
    $.ajax({
        url: "a.php",
        type: "POST",
        dataType: "json",
        data: {data: i},
        async: true,         // 默認(rèn)即為異步
        success: function(json) {
            console.log(i + ": " + json); // 打印
        }
    });
}

你們猜猜打印的那行會(huì)最終打印出什么內(nèi)容?

1: {}
2: {}
3: {}
4: {}

嗎?

錯(cuò)!

輸出的將是:

4: {}
4: {}
4: {}
4: {}

你TM在逗我?
沒有, 這并不是JS的BUG, 也不是jQuery的BUG.
這是因?yàn)? PHP休息了一秒, 而js異步地循環(huán)從1到4, 遠(yuǎn)遠(yuǎn)用不到1秒.
然后在1秒鐘后, 才開始返回?cái)?shù)據(jù), 觸發(fā)success, 此時(shí)此刻i已經(jīng)自增成了4.
自然而然地, 第一次console.log(i...)就是4, 第二次也是, 第三次也是, 第四次也是.
那么如果我們希望程序輸出也1,2,3,4這樣輸出怎么辦呢?

兩種方案:

1) 讓后端輸出i

a.php

php

page.js

JavaScriptfor( i = 1; i <= 4; i++ ){
    $.ajax({
        url: "a.php",
        type: "POST",
        dataType: "json",
        data: {data: i},
        async: true,
        success: function(json) {
            console.log(json.i + ": " + json); // 這一行改了
        }
    });
}

2) 給回調(diào)的事件對(duì)象賦屬性

a.php

php保持原代碼不變

page.js

JavaScriptfor( i = 1; i <= 4; i++ ){
    ajaxObj = $.ajax({          // 將ajax賦給ajaxObj
        url: "a.php",
        type: "POST",
        dataType: "json",
        data: {data: i},
        async: true,
        success: function(json, status, obj) {    // 增加回調(diào)參數(shù), jQuery文檔有說第三個(gè)參數(shù)就是ajax方法產(chǎn)生的對(duì)象.
                console.log(obj.i + ": " + json); // 從jQuery.ajax返回的對(duì)象中取i
        }
    });
    ajaxObj.i = i;            // 給ajaxObj賦屬性i 值為循環(huán)的i 
}
有可能你會(huì)感到困惑, 為何可以給ajaxObj設(shè)置一個(gè)i屬性然后在回調(diào)時(shí)用第三個(gè)回調(diào)參數(shù)的i屬性呢?

jQuery.ajax文檔中寫到:

jQuery.ajax( [settings ] )
settings
...
success: Function( Anything data, String textStatus, jqXHR jqXHR )
第1個(gè)參數(shù)就是響應(yīng)的文本/HTML/XML/數(shù)據(jù)/json之類的, 跟你的dataType設(shè)置有關(guān)
第2個(gè)參數(shù)就是status狀態(tài), 如success
第3個(gè)參數(shù)就是jqXHR, 也就是jQuery的XMLHttpRequest對(duì)象, 當(dāng)然, 在這里就是$.ajax()生成的對(duì)象, 也就是事件的觸發(fā)者本身, 
給本身設(shè)置一個(gè)屬性(ajaxObj.i = i), 然后再調(diào)用本身的回調(diào)時(shí), 使用本身的那個(gè)屬性(obj.i), 當(dāng)然會(huì)保持一致了.

然后
1)輸出的結(jié)果將是

1: {i:1}
2: {i:2}
3: {i:3}
4: {i:4}

2)輸出的結(jié)果將是

1: {}
2: {}
3: {}
4: {}

雖然略有區(qū)別, 但兩者均可達(dá)到要求. 若要論代碼的逼格, 相信你一定會(huì)被第二個(gè)方案給震驚的.
憑什么你給ajaxObj賦個(gè)屬性就可以在success中用了呢?

請(qǐng)看(4). 異步的回調(diào)機(jī)制

(4). 異步的回調(diào)機(jī)制 ------ 事件

一個(gè)有經(jīng)驗(yàn)的JavaScript程序員一定會(huì)將js回調(diào)用得得心應(yīng)手.
因?yàn)镴avaScript天生異步, 異步的好處是顧及了用戶的體驗(yàn), 但壞處就是導(dǎo)致流程化循環(huán)或者遞歸的邏輯明明在別的語言中無任何問題, 卻在js中無法取得期待的值...
而JavaScript異步在設(shè)計(jì)之初就將這一點(diǎn)考慮到了. 任何流行起來的JS插件方法, 如jQuery的插件, 一定考慮到了這一點(diǎn)了的.

舉個(gè)例子.

ajaxfileupload插件, 實(shí)現(xiàn)原理是將選擇的文件$.clone到一個(gè)form中, form的target設(shè)置成了一個(gè)頁面中的iframe, 然后定時(shí)取iframe的contents().body, 即可獲得響應(yīng)的值.
如果要支持multiple文件上傳(一些現(xiàn)代化的瀏覽器支持), 還是得要用`XMLHttpRequest`

如下面代碼:

$("input#file").on("change", function(e){
    for(i = 0; i < e.target.files.length; i++ ){
        var data = new FormData();
        data.append("file", e.target.files[i]);
        xmlHTTP = new XMLHttpRequest();
        xmlHTTP.open("POST", s.url);
        xmlHTTP.onreadystatechange = function(a) { // a 為 事件event對(duì)象
            if(a.target.readyState!=4)return false; // a.target為觸發(fā)這個(gè)事件的對(duì)象 即xmlHTTP (XMLHttpRequest) 對(duì)象
            try{
                console.log(a.target.responseText);
            }catch(e){
                return false;
            }
        };
        xmlHTTP.send(data);
    }
})

你可以很明顯地知道, 在onreadystatechange調(diào)用且走到console.log(a.target.responseText)時(shí), 如果服務(wù)器不返回文件名, 我們根本并不知道返回的是哪個(gè)文件的URL. 如果根據(jù)i去取的話, 那么很容易地, 我們只會(huì)取到始終1個(gè)或幾個(gè), 并不能保證準(zhǔn)確.
那么我們應(yīng)該怎么去保證在console.log(a.target.responseText)時(shí)能知道我信上傳的文件的基本信息呢?

$("input#file").on("change", function(e){
    for(i = 0; i < e.target.files.length; i++ ){
        var data = new FormData();
        data.append("file", e.target.files[i]);
        xmlHTTP = new XMLHttpRequest();
        xmlHTTP.file = e.target.files[i];
        xmlHTTP.open("POST", s.url);
        xmlHTTP.onreadystatechange = function(a) {
            if(a.target.readyState!=4)return false;
            try{
                console.log(a.target.file);         //這兒是上面`xmlHTTP.file = e.target.files[i]` 賦進(jìn)去的
                console.log(a.target.responseText);
            }catch(e){
                return false;
            }
        };
        xmlHTTP.send(data);
    }
})

是不是很簡單?

2. 展望 (1). Google對(duì)同步JavaScript的態(tài)度

在你嘗試在chrome打開的頁面中執(zhí)行async: false的代碼時(shí), chrome將會(huì)警告你:

Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user"s experience. For more help, check http://xhr.spec.whatwg.org/.

(2). 職場(chǎng)展望

異步和事件將是JavaScript工程師必備技能

[完]
Reference:

1.《Javascript異步編程的4種方法》     http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
2.《什么是 Event Loop?》            http://www.ruanyifeng.com/blog/2013/10/event_loop.html
3.《JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop》 http://www.ruanyifeng.com/blog/2014/10/event-loop.html

補(bǔ)充:
異步的數(shù)據(jù)一致性問題也可以用v1兄提供的方法來解決:

for(i=1; i < 4; i++){
    (function(i){
        $.ajax({
            url: "URL",
            type: "get",
            dataType: "text",
            success: function(response){
                console.log(response, i);
            }
        });
    })(i);
}

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

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

相關(guān)文章

  • 2017-06-27 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選漫談函數(shù)式編程一十年蹤跡的博客前端每周清單的優(yōu)勢(shì)與劣勢(shì)有望超越在嵌入式及物聯(lián)網(wǎng)的應(yīng)用現(xiàn)狀進(jìn)階系列高階組件詳解一前端之路譯如何充分利用控制臺(tái)掘金程序猿升級(jí)攻略眾成翻譯中文譯如何充分利用控制臺(tái)掘金前端從強(qiáng)制開啟壓縮探 2017-06-27 前端日?qǐng)?bào) 精選 漫談 JS 函數(shù)式編程(一) - 十年蹤跡的博客前端每周清單: Vue的優(yōu)勢(shì)與劣勢(shì);Node.js有望超越Java;JS在嵌...

    Eidesen 評(píng)論0 收藏0
  • JS高級(jí)入門教程

    摘要:解析首先簡稱是由歐洲計(jì)算機(jī)制造商協(xié)會(huì)制定的標(biāo)準(zhǔn)化腳本程序設(shè)計(jì)語言。級(jí)在年月份成為的提議,由核心與兩個(gè)模塊組成。通過引入統(tǒng)一方式載入和保存文檔和文檔驗(yàn)證方法對(duì)進(jìn)行進(jìn)一步擴(kuò)展。其中表示的標(biāo)記位正好是低三位都是。但提案被拒絕了。 JS高級(jí)入門教程 目錄 本文章定位及介紹 JavaScript與ECMAScript的關(guān)系 DOM的本質(zhì)及DOM級(jí)介紹 JS代碼特性 基本類型與引用類型 JS的垃...

    zsy888 評(píng)論0 收藏0
  • 大型網(wǎng)站技術(shù)架構(gòu)-入門梳理

    摘要:使用緩存兩個(gè)前提條件數(shù)據(jù)訪問熱點(diǎn)不均衡數(shù)據(jù)某時(shí)段內(nèi)有效,不會(huì)很快過期反向代理本地緩存分布式緩存異步旨在系統(tǒng)解耦。 大型網(wǎng)站技術(shù)架構(gòu)-入門梳理 標(biāo)簽 : 架構(gòu)設(shè)計(jì) [TOC] 羅列了大型網(wǎng)站架構(gòu)涉及到的概念,附上了簡單說明 前言 本文是對(duì)《大型網(wǎng)站架構(gòu)設(shè)計(jì)》(李智慧 著)一書的梳理,類似文字版的思維導(dǎo)圖 全文主要圍繞性能,可用性,伸縮性,擴(kuò)展性,安全這五個(gè)要素 性能,可用性,伸縮性...

    wawor4827 評(píng)論0 收藏0
  • H5學(xué)習(xí)

    摘要:為此決定自研一個(gè)富文本編輯器。本文,主要介紹如何實(shí)現(xiàn)富文本編輯器,和解決一些不同瀏覽器和設(shè)備之間的。 對(duì)ES6Generator函數(shù)的理解 Generator 函數(shù)是 ES6 提供的一種異步編程解決方案,語法行為與傳統(tǒng)函數(shù)完全不同。 JavaScript 設(shè)計(jì)模式 ② 巧用工廠模式和創(chuàng)建者模式 我為什么把他們兩個(gè)放在一起講?我覺得這兩個(gè)設(shè)計(jì)模式有相似之處,有時(shí)候會(huì)一個(gè)設(shè)計(jì)模式不能滿...

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

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

0條評(píng)論

閱讀需要支付1元查看
<