一、问题描述
有很多个请求需要依次发送,待上一个请求完成之后再发送下一个请求,发生异常时也要能够继续后面的请求。
二、思路
一个请求完成之后再发送下一个请求,关键在于发送一个之后先停下来等待该请求完成,处理之后再继续下一个请求。生成器generator里面的yield语句可以分割代码,程序遇到yield会停住,通过next语句可以一次执行一个yield分割的语句,本文尝试使用生成器完成依次发送多个请求的功能。
生成器示例如下:
1 // 生成器通过函数名前加*创建 2 function * generatorFn() { 3 yield 1; 4 yield 2; 5 } 6 // 调用生成器 7 let g = generatorFn(); 8 // 通过next方法执行,返回yield后面的值,且整个生成器未执行完之前done为false 9 console.info(g.next()); // {value: 1, done: false} 10 console.info(g.next()); // {value: 2, done: false} 11 // 执行完之后value为undefined,done为true 12 console.info(g.next()); // {value: undefined, done: true} 13 console.info(g.next()); // {value: undefined, done: true}
三、步骤
通过依次发送100个不同的请求来介绍,首先先把100个请求放入生成器内:
1 let baseUrl = 'https://jsonplaceholder.typicode.com/todos/'; 2 function* generator() { 3 for (let i = 1; i <= 100; i++) { 4 yield fetch(baseUrl + i); 5 } 6 }
接下来要先调用next()开始一个yield语句,让请求发送出去,然后处理好结果后再次调用next(),如此循环,知道next()返回done: true,通过递归实现如下:
1 function run(res) { 2 if (!res.done) { 3 res.value 4 .then((response) => response.json()) 5 .then((json) => { 6 console.log(json); 7 document.writeln('id: ' + json.id + '<br>'); 8 run(gen.next()); 9 }); 10 } 11 } 12 13 // 开始执行 14 let gen = generator(); 15 run(gen.next());
完整代码如下:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <title>fetch one by one</title> 7 <script> 8 // 构造100个请求 9 let baseUrl = 'https://jsonplaceholder.typicode.com/todos/'; 10 function* generator() { 11 for (let i = 1; i <= 100; i++) { 12 yield fetch(baseUrl + i); 13 if (i == 4) { // 故意制造一个异常 14 yield fetch('fsfdsfsdf'); 15 } else { 16 yield fetch(baseUrl + i); 17 } 18 } 19 } 20 21 22 // 处理请求结果并发送下一次请求 23 function run(res) { 24 if (!res.done) { 25 res.value 26 .then((response) => response.json()) 27 .then((json) => { 28 console.log(json); 29 document.writeln('id: ' + json.id + '<br>'); 30 run(gen.next()); 31 }) 32 .catch((err) => { // 处理一下异常 33 console.info(err); 34 run(gen.next()); 35 }); 36 } 37 } 38 // 开始执行 39 let gen = generator(); 40 run(gen.next()); 41 </script> 42 </head> 43 <body></body> 44 </html>
四、其他实现
await会强制其他代码等待,直到后面的promise执行完毕,可以使用async和await完成类似功能:
1 // 使用async和await 2 let baseUrl = 'https://jsonplaceholder.typicode.com/todos/'; 3 async function ajax() { 4 for (let i = 1; i <= 100; i++) { 5 await fetch(baseUrl + i).then((response) => response.json()) 6 .then((json) => { 7 console.log(json); 8 document.writeln('id: ' + json.id + '<br>'); 9 }) 10 .catch((err) => { // 处理一下异常 11 console.info(err); 12 }); 13 } 14 } 15 ajax();
以上项目中需要依次发送异步请求的实现方法,JS异步的发展就是让异步处理起来越来越像同步。