node 异步编程

486 阅读2分钟

异步编程包含以下几种形式:

  1. callback function
  2. promise
  3. generator function (co)
  4. async await function

callback function

嵌套太深,看起来太费劲。(不推荐使用。)

function async1(fn) {
	setTimeout(function(){
		fn('hello');
	},1)
}
function async2(fn) {
	setTimeout(function(){
		fn('world');
	},1);	
}
async1(function(data){
	async2(function(data1){
		console.log(data + ',' + data1);
	})
})

promise

  • 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
  • Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
  • pending ——>resolved——>rejected
  • new Promise(function(resolve, reject){}); // reject 可选参数
  • promise.all
  • promise.race
function promise1() {
    return new Promise((resole, reject) => {
        setTimeout(() => {
            resole("Hello"); //[@4](/user/4) 返回正确结果
        }, 1)
    })
}

function promise2(data1) {
    return new Promise((resole, reject) => {
        setTimeout(() => {
            resole(data1 + " world");
        }, 1)
    }, 1)
}

promise1()
        .then(function (v) {
            return promise2(v)
        })
        .then(function (data2) {
            console.log(data2)
        })
        .catch(function (e) {
            console.log(e)
        });

promise.all

合并请求

function timeout(duration) {
    return new Promise((resolve, reject) => {
        setTimeout(function(){
        	resolve('hello world');
        }, duration);
    });
}

var p = timeout(200).then(() => {
    return Promise.all([timeout(100), timeout(200)]);
})

p.then(v => {
	console.log(v)
})

promise.race

当有一个请求返回时,返回最新值。

var p1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 0, 'success');
});
var p2 = new Promise(function(resolve, reject) { });
var p2 = new Promise(function(resolve, reject) { });

var race = Promise.race( [p1, p2, p3] );
race.then(function(result) {
    console.log(result);
});

// Output:
// success

var race = Promise.race( [Promise.reject('failure'),
    Promise.resolve('success')] );
race.catch(function(result) {
    console.log(result);
});

// Output:
// failure

generator function

es6 的函数生成器 // 最大特点就是可以交出函数的执行权(即暂停执行),配合yield 关键字使用。

function* fibonacci() {
    yield 1;
    yield 2;
}

var it = fibonacci();
console.log(it);          // "Generator {  }"
console.log(it.next());   // 1
console.log(it.next());   // 2
console.log(it.next()); //undefined
function* foo() {
    yield 0;
    yield 1;
}
function* bar() {
    yield 'x';
    yield* foo();
    yield 'y';
}
for (let v of bar()){
    console.log(v);
};

// 输出结果:x, 0, 1, y

co (TJ)

实现原理封装了promise

var co = require('co');

co(function *(){
  // yield any promise
  var result = yield Promise.resolve(true);
}).catch(onerror);

co(function *(){
  // resolve multiple promises in parallel
  var a = Promise.resolve(1);
  var b = Promise.resolve(2);
  var c = Promise.resolve(3);
  var res = yield [a, b, c];
  console.log(res);
  // => [1, 2, 3]
}).catch(onerror);

// errors can be try/catched
co(function *(){
  try {
    yield Promise.reject(new Error('boom'));
  } catch (err) {
    console.error(err.message); // "boom"
 }
}).catch(onerror);

function onerror(err) {
  // log any uncaught errors
  // co will not throw any errors you do not handle!!!
  // HANDLE ALL YOUR ERRORS!!!
  console.error(err.stack);
}

终极解决方案 async / await

  • async/await是写异步代码的新方式,以前的方法有回调函数和Promise。
  • async/await是基于Promise实现的,它不能用于普通的回调函数。
  • async/await与Promise一样,是非阻塞的。
  • async/await使得异步代码看起来像同步代码。
  • 节约代码。
  • async/await try/catch可以同时处理同步和异步错误
const f = async() => {
	return 'hello world';
};
const testAsync = async () => {
	try {
	    const t = await f();
	    console.log(t);
		const s = await s();
	} catch(e) {
		console.log(e);
	}
};
testAsync();

同上,一样的效果

const f = () => {
    return new Promise((resole, reject) => {
        return 'hello world';
    })
}
const testAsync = async () => {
	try {
	    const t = await f();
	    console.log(t);
		const s = await s();
	} catch(e) {
		console.log(e);
	}
};
testAsync();

说明async 原理也是对promise进行了封装。