JavaScript异步操纵(续)

JavaScript环境中发生异步操纵的函数分为两大类:
计时函数
I/O函数。假如要在运用中定义庞杂的异步操纵,就要使用者两类异步函数作为基础的组织快。本文没有对某个知识点仔细睁开,仅供思绪参考。

1. 计时函数

先看一个典范的例子:

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

效果输出什么?立马输出一个5,5秒钟事后一连输出5个5(呜呜呜呜呜~),搞懂为何如许输出5,须要晓得3件事:

  • 这里只要一个i变量,作用域由var定义,不论i怎样变,都指向同一个内存地区;
  • 轮回终了后 i=== 5;
  • JavaScript事宜处置惩罚器在线程余暇之前不会实行。

来,再来和我背一遍口诀:先同步后异步末了回调。在本例子中:

  • 同步事宜:for轮回(不包含内部的setTimeout);外部的console.log(i);
  • 异步事宜:for轮回内部的setTimeout。

先实行for轮回,碰到setTimeout压入耽误事宜行列,一边轮回一边压入行列;for轮回终了实行外部的console.log(i),此时i=5,故马上输出5,此时同步事宜实行终了,接下来最先实行异步事宜setTimeout,5个setTimeout事宜守候5秒同时在守候,所以5秒终了一连输出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){};

猜猜效果是什么?

《JavaScript异步操纵(续)》

换取一下时候:

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

《JavaScript异步操纵(续)》

这里唯一想说的是:像setTimeout或是setInterval并非是准确计时的, setTimeout与setInterval在差别浏览器下的差别

2. I/O函数

这里的I/O是一个广义的观点,包含读写文件,GET或POST要求,异步读取值值函数等等。一个罕见的读文件的操纵: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的内容:

hello
world
hello
async

node fs.js:

《JavaScript异步操纵(续)》

没缺点!想象一个场景,在别的一个函数,假定名字叫panfen(),内里有一堆代码,个中须要用到从data.txt文件读取的数据,罕见的做法是把fs.readFile操纵写在panfen()内里,处置惩罚data的操纵都写在fs.readFile的callback内里,假如callback内里还要写数据呢?继承实行fs.writeFile在它的callback内里实行其他操纵…

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{
                ...
            }
        });
    }
});

这就是回调金字塔。其弊病是操纵强耦合、保护代价高。怎样做到抱负的异步呢?

《JavaScript异步操纵(续)》

心血来潮如许写:

var fs = require('fs');

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

但是,依据先同步后异步末了回调的轨则,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的特性在于可以用then要领向下通报值。

4. Generator

4.1 function*

关于生成器函数,这里不作详细引见,简朴看一例子:

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());

《JavaScript异步操纵(续)》

yieldyield*的区分:

  • yield只返回右值;
  • yield*将函数托付给另一个生成器,或可迭代的对象(字符串、数组、arguments、Map、Set)

注: yield关键字只能出现在生成器函数内里!!!不然会报错: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 的宣布,越来越多的人最先研讨async/await,听说这是异步编程终级解决方案的 。个人以为没有最好,只要更好。用这类体式格局改写:

'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();

固然,这个例子还不足以表现async/awit的上风。

6. 总结

JavaScript的异步操纵多是区分其他言语比较大的一点,也是一个难点,不过也是很风趣的。

    原文作者:芒果屋里的猫
    原文地址: https://segmentfault.com/a/1190000009131570
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞