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){};
猜猜效果是什么?
换取一下时候:
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函数
这里的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:
没缺点!想象一个场景,在别的一个函数,假定名字叫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{
...
}
});
}
});
这就是回调金字塔
。其弊病是操纵强耦合、保护代价高。怎样做到抱负的异步呢?
心血来潮如许写:
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());
yield
和yield*
的区分:
-
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的异步操纵多是区分其他言语比较大的一点,也是一个难点,不过也是很风趣的。