一批8oz的红酒杯在经历了水转印后,被送上了包装流水线,包装完成后,就可以送去激光打标了。因此在包装线上我们需要做:
挑拣➟磨口➟吹气➟套PE袋➟装箱
以上每个工艺均依赖于上一工艺,因此如果上一工艺还未完成,下一工艺就无法开始。
如果我们要完成这样的工艺,我们可以这么写代码。
function pick(){ setTimeout(()=>{ console.log('挑拣完成',new Date()); },500); } function groundMouth(){ setTimeout(()=>{ console.log('磨口完成',new Date()); },400); } function blow(){ setTimeout(()=>{ console.log('吹气完成',new Date()); },300); } function PEbag(){ setTimeout(()=>{ console.log('已套PE袋',new Date()); },200); } function pack(){ setTimeout(()=>{ console.log('装箱结束',new Date()); },100); } pick(); groundMouth(); blow(); PEbag(); pack();
结果输出如下:
装箱结束 2018-04-14T07:52:23.230Z 已套PE袋 2018-04-14T07:52:23.339Z 吹气完成 2018-04-14T07:52:23.437Z 磨口完成 2018-04-14T07:52:23.532Z 挑拣完成 2018-04-14T07:52:23.633Z
我们发现程序并没有正确的输出我们的顺序,这是由于nodejs的异步所导致的。
那如果我们要输出正确的结果,我们可以换一种写法:
function start(){ setTimeout(()=>{ console.log('挑拣完成',new Date()); setTimeout(()=>{ console.log('磨口完成',new Date()); setTimeout(()=>{ console.log('吹气完成',new Date()); setTimeout(()=>{ console.log('已套PE袋',new Date()); setTimeout(()=>{ console.log('装箱结束',new Date()); },100); },200); },300); },400); },500); } start();
这样写之后,便输出了正确的结果。
挑拣完成 2018-04-14T08:06:54.464Z 磨口完成 2018-04-14T08:06:54.873Z 吹气完成 2018-04-14T08:06:55.174Z 已套PE袋 2018-04-14T08:06:55.376Z 装箱结束 2018-04-14T08:06:55.477Z
但是这就有一个巨大的问题。如果我想在挑拣完成后再用干布擦一擦,或者在套一个PE袋之后再套一个气泡袋,这样在原代码里再加,就显得特别复杂和难以维护。
因此我们可以选择在函数体内写回调来解决这个问题。我们可以这样写:
function pick(next){ setTimeout(()=>{ console.log('挑拣完成',new Date()); next(); },500); } function groundMouth(next){ setTimeout(()=>{ console.log('磨口完成',new Date()); next(); },400); } function blow(next){ setTimeout(()=>{ console.log('吹气完成',new Date()); next(); },300); } function PEbag(next){ setTimeout(()=>{ console.log('已套PE袋',new Date()); next(); },200); } function pack(){ setTimeout(()=>{ console.log('装箱结束',new Date()); },100); } pick(()=>{ groundMouth(()=>{ blow(()=>{ PEbag(()=>{ pack(); }); }); }); });
于是,这就出现了nodejs中的回调地狱,试想,现在只是包装工艺,如果我们要加入杯身以及外协工厂的配合,这个回调会有多么的恐怖。
接下来我们的promise就要出场了。他将提供一种更加优雅的方法,让我们写回调函数
function pick(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('挑拣完成',new Date()); resolve(); },500); }); return p; } function groundMouth(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('磨口完成',new Date()); resolve(); },400); }); return p; } function blow(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('吹气完成',new Date()); resolve(); },300); }); return p; } function PEbag(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('已套PE袋',new Date()); resolve(); },200); }); return p; } function pack(){ var p=new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('装箱结束',new Date()); resolve(); },100); }); return p; } pick() .then(function(data){ return groundMouth(); }) .then(function(data){ return blow(); }) .then(function(data){ return PEbag(); }) .then(function(data){ return pack(); })
写成这样之后,就更加美观清晰和易于维护了。