• js多个异步请求,按顺序执行next


    在js里面,偶尔会遇见需要多个异步按照顺序执行请求,又不想多层嵌套,,这里和promise.all的区别在于,promise或者Jquery里面的$.when 是同时发送多个请求,一起返回,发出去的顺序是一起;这里是按照顺序发请求

    方法 一 、首先创建一个迭代器,接收任意多个函数参数

    function nextRegister(){
    			var args = arguments;
    			var count = 0;
    			var comm = {};
    			function nextTime(){
    				count++;
    				if(count < args.length){
    					if(args[count] && Object.prototype.toString.call(args[count]) == '[object Function]'){
    						args[count](comm,nextTime);
    					}
    				}
    			}
    			if(args[count] && Object.prototype.toString.call(args[count]) == '[object Function]'){
    				args[count](comm,nextTime);
    			}	
    		}  

    创建多个异步的函数,注入到迭代器中

    /*
    		 comm:多个函数,公用的变量
    		 next:调用下一个函数
    		 * */
    		function fn1(comm,next){
    			console.log('1');
    			comm.age = 20;
    			next();
    		}
    		function fn2(comm,next){
    			next();
    			console.log('2');
    			console.log(comm.age);
    		}
    		function fn3(comm,next){
    			console.log('3');
    		}
    
    //开始执行迭代
    nextRegister(fn1,fn2,fn3);
    

      在这里,fn1-fn3函数中,做异步操作,知道在异步成功的时候调用next()就可以继续执行下一个函数,同时可以将前面函数返回的结果,绑定在comm上,带到下一个函数中

    方法 二、参考express 和 koa 的写法

    1、es5写法

    	function Iterator(){
    		this.middlewares = [];
    	}
    	
    	Iterator.prototype.use = function(fn){
    		this.middlewares.push(fn);
    		return this;
    	}
    	
    	Iterator.prototype.run = function(ctx){
    		function createNext(middleware, oldNext) {
    			return function(){
    				middleware(ctx, oldNext)
    			};
    		}
    		let len = this.middlewares.length;
    		let next = function(){};
    		for (let i = len - 1; i >= 0; i--) {
    			let currentMiddleware = this.middlewares[i];
    			next = createNext(currentMiddleware, next); //从后往前遍历,前面的闭包保存后面的 next
    		}
    		next();
    	}
    	
    	var iterator = new Iterator();
    	iterator.use(function(ctx,next){
    		//这里可以做一些异步操作,只需要成功后调用 next
    		console.log("start:a");
    		next();
    		console.log("end:a");
    	});
    	
    	iterator.use(function(ctx,next){
    		console.log("start:b");
    		next();
    		console.log("end:b");
    	});
    	
    	iterator.run();
    

      

      

    2、es6 的 async 写法

    	class Iterator{
    		constructor(){
    			this.middlewares = [];
    		}
    		use(fn){
    			this.middlewares.push(fn); //存入任务
    			return this;
    		}
    		async run(ctx){
    			function createNext(middleware, oldNext) {
    				return async () => {
    					await middleware(ctx, oldNext);
    				}
    			}
    			let len = this.middlewares.length;
    			let next = async () => {
    				return Promise.resolve();
    			};
    			for (let i = len - 1; i >= 0; i--) {
    				let currentMiddleware = this.middlewares[i];
    				next = createNext(currentMiddleware, next);
    			}
    			await next();
    		}
    	}
    	
    	let app = new Iterator();
    	app.use(async (ctx,next)=>{
    		console.log("start:a");
    		await next();
    		console.log("end:a");
    	});
    	
    	app.use(async (ctx,next)=>{
    		console.log("start:b");
    		await next();
    		console.log("end:b");
    	});
    	app.run();
    

      

    三 、扩展   基于上面的 二 的迭代器,利用 node 的 原生 http 模块,可以简单的创建一个服务框架。

    这里写一个简单的静态文件查看服务

    const http = require('http');
    const fs = require("fs");
    const promisify = require("util").promisify;
    const readFile = promisify(fs.readFile);
    const readdir = promisify(fs.readdir);
    const path = require("path");
    
    //创建web服务器,提供服务,处理客户端的请求
    //普通方式监听
    class MyServer{
    	constructor() {
    		const me = this;
    	    me.middlewares = [];
    		me.methods = {};
    		me.server =  http.createServer(async (req,res)=>{
    		    //req客户端请求的相关信息,res返回响应信息
    		    //let url = req.url;
    			let ctx = {
    				res,
    				req,
    				stateCode:200,
    				headers:{'Content-Type': 'text/plain;charset=utf-8'},
    				send(str,headers){
    					let res = ctx.res;
    					res.writeHead(ctx.stateCode || 200, headers || ctx.headers);
    					res.end(str);
    				}
    			};
    			await me.run(ctx); //开始执行任务
    		});
    		me.server.on("error",function(e){
    			me.trigger("error",e);
    		});
    		me.server.on("listening",function(e){
    			  var addr = me.server.address();
    			  var bind = typeof addr === 'string'
    			    ? 'pipe ' + addr
    			    : 'port ' + addr.port;
    			  console.log('Listening on ' + bind);
    		})
    	}
    
    	listen(port){
    		this.server.listen(port || 9000);
    		return this;
    	}
    	use(fn){
    		this.middlewares.push(fn); //存入任务
    		return this;
    	}
    	async run(ctx){
    		function createNext(middleware, oldNext) {
    			return async () => {
    				await middleware(ctx, oldNext);
    			}
    		}
    		let len = this.middlewares.length;
    		let next = async () => {
    			return Promise.resolve();
    		};
    		for (let i = len - 1; i >= 0; i--) {
    			let currentMiddleware = this.middlewares[i];
    			next = createNext(currentMiddleware, next);
    		}
    		try{
    			await next();
    		}catch(e){
    			//解决中文乱码
    			this.trigger("error",e);
    		}
    	}
    	on(type,fn){
    		if(!this.methods[type]){
    			this.methods[type] = [];
    		}
    		this.methods[type].push(fn);
    	}
    	trigger(type,arg){
    		if(this.methods[type]){
    			for(var i = 0; i < this.methods[type].length; i++){
    				this.methods[type][i](arg);
    			}
    		}else if(type === "error"){
    			throw new Error(arg);
    		}
    	}
    }
    
    
    var server = new MyServer();
    
    //错误处理
    server.use(async (ctx,next)=>{
    	try{
    		await next();
    	}catch(e){
    		ctx.stateCode = 500;
    		ctx.send('服务器错误:' + e.message);
    	}
    });
    
    
    //开启跨域
    server.use(async ({res},next)=>{
    	res.setHeader("Access-Control-Allow-Origin", "*"); // 设置可访问的源
    	res.setHeader("Access-Control-Allow-Headers", "Content-Type"); 
    	next();
    });
    
    
    //其他逻辑正常处理
    const base = __dirname; //默认是当前文件为静态资源目录, 可以为  "F:\work"
    
    //尝试读取文件
    server.use(async (ctx,next)=>{
    	//初始化路径
    	if(ctx.req.url === "/"){
    		ctx.filePath = base || __dirname;
    	}else{
    		ctx.filePath = path.join(base || __dirname,decodeURIComponent(ctx.req.url));
    	}
    	
    	try{
    		let res = await readFile(ctx.filePath);
    		ctx.send(res);
    	}catch(e){
    		next();
    	}
    });
    
    //尝试读取 index.html
    server.use(async (ctx,next)=>{
    	try{
    		if(ctx.filePath.indexOf(".") === -1){
    			let res  = await readFile(ctx.filePath+"/index.html","utf-8");
    			ctx.headers["Content-Type"] = "text/html;charset=utf-8";
    			ctx.send(res);
    		}else{
    			next();
    		}
    	}catch(e){
    		next();
    	}
    });
    
    //尝试读取文件夹, 并展示
    server.use(async (ctx,next)=>{
    	try{
    		let res = await readdir(ctx.filePath);
    		var str = [];
    		var prex = ctx.req.url;
    		if(ctx.req.url !== "/"){
    			var parent  = path.dirname(ctx.req.url);
    			str = [
    				`<h3><a href="${parent}">.../返回上级</a> 共 ${res.length} 个文件</h3>`
    			];
    		}else{
    			prex="";
    		}
    		for(let  i = 0; i < res.length; i++){
    			str.push(`<p><a href="${prex}/${res[i]}">${res[i]}</a></p>`)
    		}
    		var html = `<div style="text-align:center;">${str.join("")}</div>`;
    		ctx.headers["Content-Type"] = "text/html;charset=utf-8";
    		ctx.send(html);
    	}catch(e){
    		console.log(e)
    		next();
    	}
    });
    
    //404处理
    server.use(async (ctx,next)=>{
    	ctx.stateCode = 404;
    	ctx.send('not found:'+ctx.req.url);
    });
    
    server.listen(3001);
    

      

  • 相关阅读:
    k8s 静态pod
    k8s pod资源配额对调度的影响
    mysql分库,动态数据库切换
    【转】 一个C#中的webservice的初级例子(二)
    【转】UpdatePanel 简单实例
    Linux远程mount文件系统
    【转】一个C#中webservice的初级例子(一)
    javascript读写文件
    SilverLight插件检测
    C#读写共享文件夹
  • 原文地址:https://www.cnblogs.com/muamaker/p/7743060.html
Copyright © 2020-2023  润新知