在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);

  

js多个异步请求,按顺序执行next的更多相关文章

  1. js多个异步请求

    一,两个(或多个)js异步并发执行,怎么在两个AJax异步操作之后执行一个新的操作 原题来自 ES6 方法 1.Promise 包装异步ajax操作,2.定义async 函数,3.用await等待pr ...

  2. LazyMay:实现同步和异步任务的顺序执行

    在掘金看到的文章,流程控制同步和异步任务的顺序执行,收益匪浅,工作中能用到. 1.实现以下效果 实现一个LazyMan,可以按照以下方式调用: LazyMan(“Hank”)输出: Hi! This ...

  3. js同步、异步、回调的执行顺序以及闭包的理解

    首先,记住同步第一.异步第二.回调最末的口诀 公式表达:同步=>异步=>回调 看一道经典的面试题: for (var i = 0; i < 5; i++) { setTimeout( ...

  4. 多个异步ajax请求指定顺序执行

    1.比如2个ajax请求,把第二个ajax请求放在第一个ajax请求success方法里面. 2.ajax请求时添加 async: false,//使用同步的方式,true为异步方式.结果是只有等服务 ...

  5. js的并行加载以及顺序执行

    重新温习了下这段内容,发现各个浏览器的兼容性真的是搞大了头,处理起来很是麻烦. 现在现总结下并行加载多个js的方法: 1,对于动态createElement('script')的方式,对所有浏览器都是 ...

  6. js的并行加载与顺序执行

    javaScript文件(下面简称脚本文件)需要被HTML文件引用才能在浏览器中运行.在HTML文件中可以通过不同的方式来引用脚本文件,我们需要关注的是,这些方式的具体实现和这些方式可能会带来的性能问 ...

  7. js fetch处理异步请求

    以往一直认为异步请求只能使用原生js的XMLHttpRequest或jQuery的$.ajax().$.post()等框架封装的异步请求方法 原来js还提供fetch来替代XMLHttpRequest ...

  8. silverlight——多次异步调用的顺序执行

    遇到这样一个功能需求,对于后台的同一个服务调用多次,但要求传入的参数能够再一个执行完之后再进行另一个参数的执行. 由于silverlight支持的是异步调用机制,故无法控制服务调用何时返回.那么如果使 ...

  9. 手动封装js原生XMLHttprequest异步请求

    Code Object.extend =function(targetObj,fnJson){ //扩展方法,类似于jQuery的$.extend,可以扩展类的方法,也可以合并对象 for(var f ...

随机推荐

  1. 数据库高分笔记01:事务ACID

    作者:arccosxy  转载请注明出处:http://www.cnblogs.com/arccosxy/ 事务就是一组原子性的SQL查询,或者说一个独立的工作单元.如果数据库引擎能够成功地对数据库应 ...

  2. rsync 常用参数

    rsync 常用参数的具体解释如下: -v, --verbose 详细模式输出-q, --quiet 精简输出模式-c, --checksum 打开校验开关,强制对文件传输进行校验-a, --arch ...

  3. Docker Weave网络部署

    Weave在Docker主机之间实现Overlay网络,使用业界标准VXLAN封装,基于UDP传输,也可以加密传输.Weave Net创建一个连接多个Docker主机的虚拟网络,类似于一个以太网交换机 ...

  4. 洛谷P1098 字符串的展开【字符串】【模拟】

    题目描述 在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于“d-h”或者“4-8”的字串,我们就把它当作一种简写,输出时,用连续递增的字母或数 ...

  5. hdu3374 String Problem【最小表示法】【exKMP】

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  6. 淘宝NPM镜像cnpm

    # 安装cnpm命令 npm install -g cnpm --registry=https://registry.npm.taobao.org2.cnpm install

  7. Catch That Cow POJ - 3278 bfs map超时,短路判断顺序。

    题意:可以把n边为n+1,n-1,n*2问从n到k的最少变化次数. 坑:标题写了.有点不会写bfs了... ac代码 #define _CRT_SECURE_NO_WARNINGS #include& ...

  8. samba速度调优

    本来windows上传到板子上的速度很慢 增加 socket options = TCP_NODELAY 明显上传下载速度都快了 参考: https://superuser.com/questions ...

  9. [dpdk] dpdk启动几个线程

    看别人的代码搞得有点晕,突然有点不确定,再确认一次. 使用 helloworld程序测试一下. /root/dpdk-16.07/examples/helloworld 一:  只启动一个核心. [r ...

  10. [knowledge][lisp] lisp与AI

    https://blog.youxu.info/2009/08/31/lisp-and-ai-1/ https://blog.youxu.info/2010/02/10/lisp-and-ai-2/