Node.js:与较慢的第三方合作

时间:2017-12-10 15:31:39

标签: javascript node.js asynchronous

我使用Node.js已有5年的历史,从2年开始使用这个框架的大型项目。两年来,我遇到了一个问题:如何使用非异步第三方应用程序(如MySQL,MongoDB或Apache SolR)异步和快速地工作?

我曾经使用过承诺并准备了几个承诺请求,如下所示:

const promises = []

for (let i = 0; i < 1000; i += 1) {
  const promise = mySqlRequest()
  promises.push(promise)
}

Promise.all(promises)
.then()
.catch()

这个例子可以工作,但会同时向MySQL服务器发送1000个请求,他们会堆叠这些请求并变得非常慢,会消耗非常大量的RAM。

最好的解决方案是只做一个大的请求,但在某些情况下它是不可能的,我被迫做出递归函数, 归结为同步和慢。

那么,使用Node.js和堆叠第三方快速和异步工作的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

如果一次发送所有请求不起作用并且逐个发送它们也不起作用,则需要类似于线程池的内容,其中一些任意数量的任务同时执行。这很容易使用promises实现,例如:

Promise.pooled = function(arr, num = 5) {
    return new Promise(function(resolve, reject) {
        var i = -1;
        var error = false;

        var end = function() {
            num--;
            if(num === 0) resolve();
        }

        var next = function() {
            if(error) return;
            i++;
            if(i >= arr.length)
                end();
            else
                arr[i]().then(next).catch(onerr);
        }

        var onerr = function() {
            if(error) return
            error = true
            reject.call(arguments)
        }

        for(var j = 0; j < num; j++)
            next()
    });
}

这允许你传递一个数组的函数作为第一个参数,这些函数应该不带参数并返回一个promise。然后它将同时执行num。如果其中一个承诺失败,它将失败自己的承诺并停止执行(这很容易改变)。

示例:

Promise.after = function(ms) {
    return new Promise(function(resolve) {
        setTimeout(resolve, ms)
    });
}

Promise.pooled = function(arr, num = 5) {
	return new Promise(function(resolve, reject) {
		var i = -1;
		var error = false;
		
		var end = function() {
			num--;
			if(num === 0) resolve();
		}
		
		var next = function() {
			if(error) return;
			i++;
			if(i >= arr.length)
				end();
			else
				arr[i]().then(next).catch(onerr);
		}
		
		var onerr = function() {
			if(error) return
			error = true
			reject.call(arguments)
		}
		
		for(var j = 0; j < num; j++)
			next()
	});
}

var test = [
	afterH(1000),
	afterH(500),
	afterH(800),
	afterH(600),
	afterH(3000),
	afterH(300),
	afterH(900),
	afterH(2000),
	afterH(1500),
	afterH(900),
	afterH(700),
	afterH(600),
	afterH(700)
];

// helper function, returns a function which when invoked returns a promise
function afterH(ms) {
	return function() {
		console.log("Starting one job")
		return Promise.after(ms);
	}
}

Promise.pooled(test, 3).then(function() {console.log("All jobs finished") }).catch(function() {console.log("Job failed")})