求分析 Async, Promise, EventProxy 优劣,Nodejs中哪个更适合服务端用来减少回调(可维护性,效率)

求分析 Async, Promise, EventProxy 优劣,Nodejs中哪个更适合服务端用来减少回调(可维护性,效率)

请前辈试从可维护性,执行效率,开发效率等方面分析。

另外在node中,Async和Promise之间的效率差是否可以忽略?

7 回复

Async, Promise 和 EventProxy 的优劣分析

在 Node.js 中,处理异步操作的常见方式有三种:Async, Promise, 和 EventProxy。每种方法都有其独特的优点和缺点。以下是针对可维护性、执行效率和开发效率的详细分析。

1. 可维护性

  • Promise:
    • 优点: 使用链式调用的方式,使得代码结构清晰,易于理解。
    • 缺点: 链式调用过长时可能导致代码难以阅读和维护。
const promiseExample = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve('First Task'), 1000);
    }).then(result => {
        console.log(result);
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve('Second Task'), 1000);
        });
    }).then(result => {
        console.log(result);
    });
};
  • Async/Await:
    • 优点: 通过 await 关键字简化了异步代码的编写,使得代码看起来更像同步代码,提高了可读性和可维护性。
    • 缺点: 错误处理可能需要额外的 try...catch 块。
const asyncExample = async () => {
    try {
        const result1 = await new Promise((resolve) => setTimeout(() => resolve('First Task'), 1000));
        console.log(result1);
        const result2 = await new Promise((resolve) => setTimeout(() => resolve('Second Task'), 1000));
        console.log(result2);
    } catch (error) {
        console.error(error);
    }
};
  • EventProxy:
    • 优点: 通过事件驱动的方式处理异步任务,适用于事件驱动的场景。
    • 缺点: 代码复杂度较高,不易于理解和维护。
const eventproxyExample = () => {
    const eventproxy = require('eventproxy');
    const ep = new eventproxy();
    
    ep.after('task', 2, (results) => {
        console.log(results[0], results[1]);
    });

    setTimeout(() => ep.emit('task', 'First Task'), 1000);
    setTimeout(() => ep.emit('task', 'Second Task'), 1500);
};

2. 执行效率

  • PromiseAsync/Await 在执行效率上几乎相同,因为它们都基于 JavaScript 的事件循环机制。
  • EventProxy 由于引入了事件机制,可能会稍微增加一些额外的开销。

3. 开发效率

  • PromiseAsync/Await 提供了简洁的语法,使得异步代码更容易编写和调试。
  • EventProxy 虽然提供了灵活的事件驱动模式,但需要更多的配置和代码量,开发效率较低。

结论

在大多数情况下,Async/Await 是最佳选择,因为它提供了简洁的语法和良好的可维护性。而 Promise 也有类似的优势,只是在某些情况下链式调用可能变得复杂。EventProxy 适用于特定的事件驱动场景,但在一般情况下并不是首选。

希望这些分析对您有所帮助!


沒用過event proxy… 以下說法只考慮async 和promise

個人推介用promise >> async #執行效率 沒有實測... 留其他朋友補充...

#可讀性方面 跟你要處理的課題有關

##例子1: 你有一串數據都要用同一個函數處理 async 用法跟underscore 感覺差不多

async.map(['file1','file2','file3'], fs.stat, function(err, results){
    // results is now an array of stats for each file
});

同樣的代碼用 (一個promise library)寫

Q.allSettled([
    Q.nfapply(FS.stat, ["file1"]),
    Q.nfapply(FS.stat, ["file2"]),
]).then(function (results) {
    console.log(results);                                                                                                                                                
})
.done(); //End the chain and throw any unhandle errors

aync 在這情況比Q 易讀

##例子2: 你要處理一些同步的功能像讀database

async.waterfall([
    function(callback){
	db = connectDb(); 
        callback(null, db);
    },
    function(arg1, callback){
      // arg1 now equals 'db'
	query = arg1.query('select * from user');
        callback(null, query);
    },
    function(arg1, callback){
        // arg1 now equals 'query'
	// process arg1.....
        callback(null, 'done');
    }
], function (err, result) {
   // result now equals 'done'    
});

Q 的寫法, 假設這次所有database 函數都會回傳Q promise

connectDb()
	.then(function (db) {
		return db.query('select * from user');
	})
	.then(function (query) {
		return query.process();
	})
	.then(function (results) {
		console.log(results);
		return results;
	})
	.done();

Q 在這情況比較好 因為它很像傳統的同步函數寫法. 如果加上錯誤處理 Q的可讀性應該更好...

以上例子都是async, q 的一些粗淺的用法... 應該會有更短更漂亮的演繹

我想帶出的是 用Q能表達一個直觀的線性思維.

不過兩者沒有衝突 可以混合一起用...不過我能用Q都用Q解決問題的

#開發效率方面... 如果從未用過promise, async會好promise 一點點

因為現在大部份的library 都只支援callback

fs.stat(path, callback);

async 天生和它們的親和力強, 因為它就是用這個callback 幹活的…

用promise 的話 你要先自行轉換callback做promise

var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (error, text) {
    if (error) {
        deferred.reject(new Error(error));
    } else {
        deferred.resolve(text);
    }
});
return deferred.promise;

當然Q 也提供了short cut

Q.nfapply(FS.readFile, ["foo.txt", "utf-8"])
      .then(function (text) {
         console.log(text);
      }); 

兩段代碼都在做同樣的事: 把callback 轉為promise

以上就是我對這兩個library 的觀感,有錯請指出

很感谢您写了这么多,对一个新人来说太有帮助了。

Q不错 可以考虑使用Generator

当然是用 Promise 啦

因为 ES6 里提供了 Promise (最新版的 firefox 和 chrome 都有,node 应该很快也会有了吧?),目前也可以通过 npm 里的 es6-promise 来调用

Promise 还可以与 Generator 结合,用法参考 mozilla 的 task.js 和 TJ 大神的 co

例子一如果用 bluebird 配合 bluebird 提供的 .promisifyAll 功能来做的话,可以写成这样:

var fs = Primise.promisifyAll(require('fs'))

Promise.all( [‘file1’,‘file2’,‘file3’].map(function(fname) { return fs.statAsync(fname) }) ) .then(function(results) { // handle results }) .catch(function(err) { console.error(err.stack) })

同样的,所有符合 function(err, result) {} 这种规范的接口,都可以用它的 .promisify 转化为 Promise 风格的接口,和 Q 提供的 Q.nfcall 或者 Q.nfapply 类似,但是方便很多。

例子二可以补充一点,用 bluebird 不需要加 .done 强制抛出异常,bluebird 默认会提供一个 exceptionHandler。

async 只是个方便处理回调的工具库,为各种异步场景提供相应的工具函数;而 Promise 是一种规范化异步接口,方便异步接口封装、处理的东西,它已经成了标准,目前仍有许多实现版本,但终归会趋于稳定,成为标准做法(要不要加之一?)。

分析

在Node.js中,Async, Promise, 和 EventProxy 都是处理异步操作的重要工具。每种工具都有其独特的应用场景和优势。下面我们从可维护性、执行效率和开发效率三个方面来分析它们。

1. 可维护性

  • Async: 使用 async/await 可以显著提高代码的可读性和可维护性。通过使用 await 关键字,你可以将异步操作写得像同步代码一样,使得代码逻辑更加清晰。

    async function fetchData() {
      try {
        const data1 = await getDataFromApi1();
        const data2 = await getDataFromApi2(data1);
        return data2;
      } catch (error) {
        console.error(error);
      }
    }
    
  • Promise: Promise 提供了一种更现代的方式来处理异步操作,通过 .then().catch() 方法来处理成功和失败的情况。它比传统的回调函数更容易管理和理解。

    getDataFromApi1()
      .then(data1 => getDataFromApi2(data1))
      .then(data2 => console.log(data2))
      .catch(error => console.error(error));
    
  • EventProxy: EventProxy 是一个专门用于事件驱动编程的库,适用于需要处理多个异步事件的情况。它的优点在于可以灵活地管理复杂的事件流。

    const EventProxy = require('eventproxy');
    const proxy = new EventProxy();
    
    proxy.all('data1', 'data2', (data1, data2) => {
      console.log(data2);
    });
    
    proxy.trigger('data1', await getDataFromApi1());
    proxy.trigger('data2', await getDataFromApi2(await getDataFromApi1()));
    

2. 执行效率

  • Promiseasync/await 在执行效率上相差不大,因为它们都是基于微任务队列的机制。但是,async/await 由于语法糖的优势,编译后的代码可能更容易被优化。
  • EventProxy 的执行效率取决于事件触发的次数和复杂度。如果事件数量多且复杂,可能会带来一些性能开销。

3. 开发效率

  • Async/Await: 因为代码看起来像同步代码,所以开发效率最高。开发者不需要学习复杂的回调模式或事件驱动模式。
  • Promise: 开发效率较高,但需要理解 .then().catch() 的用法。
  • EventProxy: 开发效率较低,因为需要引入额外的库,并且需要理解事件驱动的编程模式。

结论

在大多数情况下,async/await 是最推荐的选择,因为它在可维护性、执行效率和开发效率方面表现最佳。而 PromiseEventProxy 则在特定场景下可能更有优势。

回到顶部