代码如下://请求user.jsonfetch('/article/promise-chaining/user.json')//加载为json。then(response=>response.json())//向GitHub发起请求.then(user=>fetch(`https://api.github.com/users/${user.name}`))//将响应加载为json.then(response=>response.json())//显示头像图像(githubUser.avatar_url)3秒(也许是动画).then(githubUser=>{letimg=document.createElement('img');img.src=githubUser.avatar_url;img.className="promise-avatar-example";document.body.append(img);setTimeout(()=>img.remove(),3000);//(*)});这里的语义比较清晰,每次then调用返回一个Promise,后面的then调用必须在上一个then调用返回的Promiseresolved之后执行。但是,上面的代码有一个缺陷:看*:行的代码,在头像显示和移除之后,如果我们想增加一些额外的处理逻辑,我们应该怎么做呢?例如,我们想要显示一个用于编辑该用户或其他内容的表单。为了使链具有可扩展性,我们需要返回一个Promise,该Promise在头像完成显示时解析。代码如下:fetch('/article/promise-chaining/user.json').then(response=>response.json()).then(user=>fetch(`https://api.github.com/users/${user.name}`)).then(response=>response.json()).then(githubUser=>newPromise(function(resolve,reject){//(*)letimg=document.createElement('img');img.src=githubUser.avatar_url;img.className="promise-avatar-example";document.body.append(img);setTimeout(()=>{img.remove();resolve(githubUser);//(**)},3000);}))//3秒后触发.then(githubUser=>alert(`Finishedshowing${githubUser.name}`));也就是说,()行中的.then处理程序现在返回新的Promise,它仅在setTimeout(*)中的resolve(githubUser)调用解决后才解决。链中的下一个.then将等待它。下图中第5行新建的Promise对象会在第13行resolve,而这个resolve操作会触发第17行的then方法等待它。作为一种好的做法,异步操作应该始终返回一个Promise。这使得计划之后的行动成为可能;即使我们现在不打算扩展链,我们以后可能会需要它。最后我们重构代码。functionloadJson(url){returnfetch(url).then(response=>response.json());}上面的函数返回一个Promise,当response的json数据可用时,在promise之后注册的.then函数将被触发。看它的消费代码:当第26行then中的箭头函数被触发时,user是第25行的user.json数据反序列化后形成的JSON对象。functionloadGithubUser(name){returnloadJson(`https://api.github.com/users/${name}`);}只是对loadJson的一层封装,调用者不需要知道具体的Github用户api的端点.functionshowAvatar(githubUser){returnnewPromise(function(resolve,reject){letimg=document.createElement('img');img.src=githubUser.avatar_url;img.className="promise-avatar-example";document.body.append(img);setTimeout(()=>{img.remove();resolve(githubUser);},3000);});}返回一个Promise,在其中写业务逻辑executor,并通过resolve(githubUser)将Promise状态设置为fulfilled以备将来扩展。完整代码在最后://使用它们:loadJson('/article/promise-chaining/user.json').then(user=>loadGithubUser(user.name)).then(showAvatar).then(githubUser=>警报(`已完成显示${githubUser.name}`));//...总结一下,如果.then(或catch/finally,无关紧要)处理程序返回一个Promise,Promise链的其余部分将等待直到这个未决的Promise被解决。当Promise内部的executor有数据被resolve调用时,resolve输入的数据(或error)会进一步传递给Promise链中的其他Promise.then。
