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

資訊專欄INFORMATION COLUMN

JavaScript異步操作(續(xù))

Travis / 654人閱讀

摘要:環(huán)境中產(chǎn)生異步操作的函數(shù)分為兩大類計時函數(shù)和函數(shù)。如果要在應(yīng)用中定義復(fù)雜的異步操作,就要使用者兩類異步函數(shù)作為基本的構(gòu)造快。在本例子中同步事件循環(huán)不包含內(nèi)部的外部的異步事件循環(huán)內(nèi)部的。其弊端是操作強(qiáng)耦合維護(hù)代價高。

JavaScript環(huán)境中產(chǎn)生異步操作的函數(shù)分為兩大類:計時函數(shù)I/O函數(shù)。如果要在應(yīng)用中定義復(fù)雜的異步操作,就要使用者兩類異步函數(shù)作為基本的構(gòu)造快。本文沒有對某個知識點(diǎn)細(xì)致展開,僅供思路參考。
1. 計時函數(shù)

先看一個經(jīng)典的例子:

for(var i = 0;i < 5; i++){
    setTimeout(function(){
        console.log(i);
    },5000);
}
console.log(i);

結(jié)果輸出什么?立馬輸出一個5,5秒鐘過后連續(xù)輸出5個5(嗚嗚嗚嗚嗚~),搞懂為什么這樣輸出5,需要知道3件事:

這里只有一個i變量,作用域由var定義,不管i怎么變,都指向同一個內(nèi)存區(qū)域;

循環(huán)結(jié)束后 i=== 5;

JavaScript事件處理器在線程空閑之前不會執(zhí)行。

來,再來和我背一遍口訣:先同步后異步最后回調(diào)。在本例子中:

同步事件:for循環(huán)(不包含內(nèi)部的setTimeout);外部的console.log(i);

異步事件:for循環(huán)內(nèi)部的setTimeout。

先執(zhí)行for循環(huán),遇到setTimeout壓入延遲事件隊列,一邊循環(huán)一邊壓入隊列;for循環(huán)結(jié)束執(zhí)行外部的console.log(i),此時i=5,故立即輸出5,此時同步事件執(zhí)行完畢,接下來開始執(zhí)行異步事件setTimeout,5個setTimeout事件等待5秒同時在等待,所以5秒結(jié)束連續(xù)輸出5個5。

再看一個例子:

var start = new Date;
setTimeout(function(){
    var end = new Date;
    console.log("time using:" + (end - start) + "ms");
},5000);
while(new Date - start < 1000){};

猜猜結(jié)果是什么?

調(diào)換一下時間:

var start = new Date;
setTimeout(function(){
    var end = new Date;
    console.log("time using:" + (end - start) + "ms");
},2000);
while(new Date - start < 5000){};

這里唯一想說的是:像setTimeout或是setInterval并非是精確計時的, setTimeout與setInterval在不同瀏覽器下的差異。

2. I/O函數(shù)

這里的I/O是一個廣義的概念,包括讀寫文件,GET或POST請求,異步讀取值值函數(shù)等等。一個常見的讀文件的操作:fs.js

var fs = require("fs");

fs.readFile("data.txt",function(err,data){
    if(err){
        return console.log(err);
    }
    console.log(data.toString())
});

data.txt的內(nèi)容:

hello
world
hello
async

node fs.js:

沒毛病!設(shè)想一個場景,在另外一個函數(shù),假設(shè)名字叫panfen(),里面有一堆代碼,其中需要用到從data.txt文件讀取的數(shù)據(jù),常見的做法是把fs.readFile操作寫在panfen()里面,處理data的操作都寫在fs.readFile的callback里面,如果callback里面還要寫數(shù)據(jù)呢?繼續(xù)執(zhí)行fs.writeFile在它的callback里面執(zhí)行其他操作...

var fs = require("fs");

fs.readFile("data.txt",function(err,data){
    if(err){
        return console.log("failed to read data!");
    }else{
        fs.writeFile("./data_copy.txt", data, function(){
            if(err){
                ...
            }else{
                ...
            }
        });
    }
});

這就是回調(diào)金字塔。其弊端是操作強(qiáng)耦合、維護(hù)代價高。如何做到理想的異步呢?

靈機(jī)一動這樣寫:

var fs = require("fs");

var data = fs.readFile("data.txt",function(err,data){
    return data ? data : err;
});
fs.writeFile("./data_copy.txt", data, function(){
    ...
});

然而,根據(jù)先同步后異步最后回調(diào)的法則,fs.writeFile里面使用到的data,肯定是undefined

3.Promise
var fs = require("fs")

function myReadFile(filepath) {
    return new Promise(function (resolve, reject) {
        fs.readFile(filepath, function (err, data) {
            data ? resolve(data) : reject(err);
        });
    });
}

function myWriteFile(filepath,data) {
    return new Promise(function (resolve, reject) {
        fs.writeFile(filepath,data,function (err) {
            err ? reject(err) : resolve();
        });
    });
}

function test() {
    myReadFile("data.txt").then(function(data){
        myWriteFile("./data1.txt",data)
    });
}
test();

Promise的特點(diǎn)在于可以用then方法向下傳遞值。

4. Generator 4.1 function*

關(guān)于生成器函數(shù),這里不作具體介紹,簡單看一例子:

function* GenFunc(){
    yield [1,2];
    yield* [3,4];
    yield "56";
    yield* "78"  
}
var gen = GenFunc();
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());

yieldyield*的區(qū)別:

yield只返回右值;

yield*將函數(shù)委托給另一個生成器,或可迭代的對象(字符串、數(shù)組、arguments、Map、Set)

注: yield關(guān)鍵字只能出現(xiàn)在生成器函數(shù)里面!!!否則會報錯:Unexpected strict mode reserved word

4.2 co

co是基于Generator的一個庫:

var fs = require("fs");
var co = require("co");

function myReadFile(filepath){
    return function(cb){
        fs.readFile(filepath,cb);
    };
}

function myWriteFile(filepath,data){
    return function(cb){
        fs.writeFile(filepath,data,cb);
    };
}

co(function* GenFunc(){
    var data = yield myReadFile("data.txt");
    yield myWriteFile("data1.txt",data);
}).catch(function(err){
    console.log(err);
});

看起來是不是神清氣爽?

4.3 Koa

Koa是基于Generator和co的web框架。

var koa = require("koa");
var app = koa();

app.use(function* (next){
    console.log(1);
    yield next;
    console.log(3);
});
app.use(function* (){
    console.log(2);
    this.body = "hello Koa!";
});
app.listen(8080);

啟動程序,流浪器輸入localhost:8080,看到頁面有hello Koa!,控制臺輸入1 2 3

5.async/awit

隨著 Node 7 的發(fā)布,越來越多的人開始研究async/await,據(jù)說這是異步編程終級解決方案的 。個人覺得沒有最好,只有更好。用這種方式改寫:

"use strict"
var fs = require("fs")

function myReadFile(filepath) {
    return new Promise(function (resolve, reject) {
        fs.readFile(filepath, function (err, data) {
            data ? resolve(data) : reject(err);
        });
    });
}

function myWriteFile(filepath,data) {
    return new Promise(function (resolve, reject) {
        fs.writeFile(filepath,data,function (err) {
            err ? reject(err) : resolve();
        });
    });
}

async function test() {
    const data = await myReadFile("data.txt");
    await myWriteFile("./data1.txt",data);
}
test();

當(dāng)然,這個例子還不足以體現(xiàn)async/awit的優(yōu)勢。

6. 總結(jié)

JavaScript的異步操作可能是區(qū)別其他語言比較大的一點(diǎn),也是一個難點(diǎn),不過也是很有趣的。

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

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

相關(guān)文章

  • 編寫自己的代碼庫(javascript常用實(shí)例的實(shí)現(xiàn)與封裝--續(xù)

    摘要:前言這個系列的上一篇文章編寫自己的代碼庫常用實(shí)例的實(shí)現(xiàn)與封裝總結(jié)了個常見的操作。前序修改以及寫法優(yōu)化此處修改之前提交函數(shù)已經(jīng)發(fā)現(xiàn)的,基于這個系列上篇文章的提供的函數(shù)。 1.前言 這個系列的上一篇文章(編寫自己的代碼庫(javascript常用實(shí)例的實(shí)現(xiàn)與封裝))總結(jié)了34個常見的操作。但是在開發(fā)中,常見的實(shí)例又何止這么多個,經(jīng)過這些日子的探索,以及他人的意見,現(xiàn)在得追加一些操作實(shí)例了。...

    Atom 評論0 收藏0
  • ES6 異步編程之三:Generator續(xù)

    摘要:前言在異步編程之一中實(shí)現(xiàn)了一個異步函數(shù)調(diào)用鏈,它是一個順序調(diào)用鏈,很類似責(zé)任鏈模式,但現(xiàn)實(shí)往往不是平鋪直敘的,更多的其實(shí)是峰回路轉(zhuǎn),本文將繼續(xù)討論更多的用法。 前言 在《ES6 異步編程之一:Generator》中實(shí)現(xiàn)了一個異步函數(shù)調(diào)用鏈,它是一個順序調(diào)用鏈,很類似責(zé)任鏈模式,但現(xiàn)實(shí)往往不是平鋪直敘的,更多的其實(shí)是峰回路轉(zhuǎn),本文將繼續(xù)討論更多Generator的用法。 作為函數(shù)的Gen...

    JiaXinYi 評論0 收藏0
  • 次時代Java編程(一):續(xù) vertx-sync實(shí)踐

    摘要:定時器例子之前通過調(diào)用定時器,需要傳一個回調(diào),然后所有的代碼邏輯都包在里面。這里定時器會阻塞在這一行,直到一秒后才會執(zhí)行下面的一行。 之前介紹過quasar,如果你希望在vert.x項目里使用coroutine的話,建議使用vertx-sync。本篇將介紹vertx-sync。 showImg(/img/bVzIsu); 本來打算另起一篇,寫其他方面的東西,但是最近比較忙,就先寫一篇實(shí)...

    vpants 評論0 收藏0
  • 為什么 Math.min() 比 Math.max() 大?(續(xù)

    摘要:本來以為是無參調(diào)用時返回了運(yùn)算的幺元,后來細(xì)琢磨,好像沒有什么關(guān)系,對于運(yùn)算集合上的二元運(yùn)算,如果滿足,則是運(yùn)算的幺元。乘法運(yùn)算的幺元是,因為。但是我們定義函數(shù)或者函數(shù),如果不傳遞參數(shù)時,返回幺元的話也是不合理的。 昨天心血來潮寫了一篇文章:為什么Math.min() 比 Math.max() 大? 為什么很多人會有這種疑惑,是因為犯了想當(dāng)然的錯誤——望文生義。Math.min() 作...

    xiguadada 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<