从回调地狱到 Promise基本用法使用then()处理成功的返回值ressuperagent.get(https://dog.ceo/api/breed/${data}/images/random).then((res){console.log(res.body.message);fs.writeFile(dog-img.txt,res.body.message,(err){if(err)returnconsole.log(err.message);console.log(随机小狗图片链接已经保存);});})使用catch来捕获请求过程中的错误constfsrequire(fs);constsuperagentrequire(superagent);fs.readFile(${__dirname}/dog.txt,(err,data){console.log(品种:${data});superagent.get(https://dog.ceo/api/breed/${data}/images/random).then((res){console.log(res.body.message);fs.writeFile(dog-img.txt,res.body.message,(err){if(err)returnconsole.log(err.message);console.log(随机小狗图片链接已经保存);});}).catch((err){console.log(err.message);});});这个HTTP请求这一步现在已经用Promise的方式变成了链式调用但是外层的读取文档和内层的存储文档仍然还是回调这确实是一个半吊子的改造因为局部的Promise无法根除回调嵌套构造Promise回顾第一步刚开始的适合我们使用了三个异步请求嵌套的方式来撰写代码这样的代码又三层的缩进错误处理非常分散每个回调函数的错误处理都需要单独处理而且可读性特别差看上面的代码我们修改的第一个版本我们发现superagent本身就支持Promise我们使用.then/catch把请求的部分修改了这个时候请求的部分已经看上去整齐了一点错误也可以通过catch来捕获了但是阅读文件和写入的文件还是使用的回调函数的方式整个代码仍然在外层的回调函数里面将fs.readfile也变成Promise那现在我们就知道了想要取消外层的回调函数我们必须让fs.readfile返回一个Promise而不是接受一个回调的方式用new Promise将原来的fs.readfile包起来new Promise的基本结构如下newPromise((resolve,reject){// 在这里执行异步操作// 成功时调用 resolve(结果)// 失败时调用 reject(错误)});这里的resolve和reject是两个函数这个都是Promise内部提供的所以我们要将之前的err,data包装成reslove和reject现在我们就来包装fs.readfileconstreadFilePro(file){returnnewPromise((resolve,reject){fs.readFile(file,(err,data){if(err)reject(没有找到这个文件);resolve(data);});});};这里我们定义了一个readFilePro函数需要传入一个文件路径然后会返回一个Promise然后再Promise执行器里面调用原来的fs.readfile,如果回调操作失败就调用reject如果成功就调用resolve(data)然后把读取到的数据传递出去这样我们就拥有了一个Promise版本的读文件函数fs.writeFile包装fs.writeFile的包装和fs.readfile一模一样这里就直接展示代码constwriteFilePro(file,data){returnnewPromise((resolve,reject){fs.writeFile(file,data,(err){if(err)reject(无法读取这个文件);resolve(success);});});};改写主流程现在我们手上有readFilePro、writeFilePro,已经本身就支持Promise的superagent.get现在就简单了我们直接使用then来实现链式调用就可以了readFilePro(${__dirname}/dog.txt).then((data){console.log(品种${data});returnsuperagent.get(https://dog.ceo/api/breed/${data}/images/random);}).then((res){console.log(res.body.message);returnwriteFilePro(dog-img.txt,res.body.message);}).then((){console.log(随机小狗图片链接已保存到文件中);}).catch((err){console.log(err.message);});链式调用流程readFilePro返回一个Promise成功会得到一个文件内容第一个.then会打印狗的品种然后会返回一个Promise再传给下一个.then第二个.then会打印狗图片的URL同样返回Promise等链接写完传给下一步第三个.then这个时候文件已经写完了打印最终成功信息.catch上述的链式调用任何一个环节出现问题都会跳到这里来统一处理虽然现在已经是扁平化的代码风格了但是.then()多的时候仍然会有点绕变量需要一路传递一下之后我们将使用Async/Await 让这段代码变得更好