三个在JavaScript异步编程中常用的ployfill工具:
1 function timeoutify(f,t){ 2 //作用:对异步函数做超时检测,当异步函数在指定的时间内完成时才让它调用传入的回调 3 let id=setTimeout(()=>{ 4 id=undefined; 5 },t); 6 return function(){ 7 if (id){ 8 //id还存在说明没有超时 9 clearTimeout(id); 10 f.apply(this,arguments); 11 }else{ 12 //id是undefined说明超时了 13 f(Error(`Refuse to execute the callback beacuse of Timeout.`)); 14 } 15 }; 16 } 17 18 function asyncify(f){ 19 //作用:避免出现Zalgo竞态条件,使异步函数对回调的调用始终是异步调用 20 let id,origin_f; 21 id=setTimeout(()=>{ //使用hack=setTimeout(0)检测回调是否被异步调用 22 id=undefined; 23 if (f){ //能进入这个if语句,说明回调被同步调用 24 f(); //使用hack-setTimeout(0)对这个回调强制进行异步调用 25 } 26 },0); 27 origin_f=f; 28 f=null; 29 return function _result(){ 30 //原理:当调用asyncify时,立刻进行setTimeout(0)倒计时,只有是同步调用,才会导致触发_result时id存在值 31 if (id){ 32 //id还存在说明出现了Zalgo,即这个回调被同步调用了,要避免这种情况 33 f=origin_f.bind.apply(origin_f,[this].concat([].slice.call(arguments))); //arguments作为科里化参数 34 }else{ 35 //已经是异步了,正常执行 36 origin_f.apply(this,arguments); 37 } 38 }; 39 } 40 41 function promiseify(f){ 42 //作用:将一个传统的异步函数promise化 43 /* 44 传入的异步函数要求: 45 1.最后一个参数是回调函数 46 2.这个回调函数使用error-first风格 47 promiseify返回一个新函数,新函数的参数列表移除了原函数参数列表的回调函数,其他参数相同 48 */ 49 return function(){ 50 return new Promise((ok,fail)=>{ 51 let args=[].slice.call(arguments); 52 args.push(function(err,data){ //传入用于断定promise决议结果的函数作为原函数的回调函数 53 if(err) 54 fail(err); //ok和fail函数本身不返回值(即返回undefined) 55 else 56 ok(data); 57 58 }); 59 f.apply(this,args); 60 }); 61 }; 62 }