Promise解决回调地狱 发表于 2018-12-05 | 分类于 JavaScript 从回调到Promise 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384// index.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>异步demo</title></head><body>用户: <span id="user"></span><hr>分组: <span id="groups"></span><hr>其中第一个群含有成员: <span id="members"></span><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script><script src="./main.js"></script></body></html>// user.json{ "name": "zhangyang", "id": 1}// group.json[ {"name": "11班","id": 1}, {"name": "12班","id": 2}]// group_member.json[ {"name": "张扬","id": 11}, {"name": "张琴","id": 21}]// main.js$.ajax({ url: './user.json', method: 'get', success: onGetUser, error: onError})function onGetUser(data){ $('#user').text(data.name) $.ajax({ url: './group.json?id=' + data.id, method: 'get', success: onGetGroup, error: onError })}function onGetGroupMember(data){ $('#members').text([data[0].name, data[1].name].join(','))}function onError(){ alert('服务器繁忙,你先去一边儿待着')}function onGetGroup(data){ $('#groups').text([data[0].name, data[1].name].join(',')) $.ajax({ url: './group_member.json?group_id=' + data[0].id, method: 'get', success: onGetGroupMember, error: onError })}// main-promise.js // Promise解决上述回调地狱,使代码优美$.get('./user.json').then(function(data){ $.get('./group.json?id=' + data.id).then(function(data){ $.get('./group_member.json?group_id=' + data[0].id).then(function(){ console.log('成功') },onError) },onError)},onError)function onError(){ console.log('被雷劈')} 创造一个Promise对象1234567891011121314151617181920212223242526272829303132333435// 普通异步函数function rollDice(callback){ setTimeout(function(){ console.log('开始摇') let random = Math.random() if(random > 0.5){ callback('大') }else{ callback('小') } })}let result = rollDice(function(data){ console.log(data)})// promise-marker.jsfunction rollDice(){ return new Promise(function(resolve,reject){ setTimeout(function(){ console.log('开始摇') let random = Math.random() if(random > 0.5){ resolve('大') }else{ resolve('小') } },1000) })}let result = rollDice()result.then(function(bigOrSmall){ console.log(bigOrSmall)}) Promise实际使用场景Promise + ajax场景一123456789101112131415161718192021222324252627282930313233343536373839// index.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>异步demo</title></head><body>用户: <span id="user"></span><hr>分组: <span id="groups"></span><hr>其中第一个群含有成员: <span id="members"></span><form action="./user.json" method="post"> <input type="text" name="username" placeholder="username"> <input type="text" name="password" placeholder="password"> <input type="submit" value="提交"></form><script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script><script src="./main.js"></script></body></html>// main.js$('form').on('submit',function(e){ e.preventDefault() $('form input[type=submit]').prop('disabled',true) getUser() .then(data => { $('form input[type = submit]').prop('disabled',false) })})function getUser(){ return $.post('./user.json',{username: 'xxx'}) .then(data => {console.log(data)},xhr => {alert('error')})} Promise + ajax场景二12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273// 原生ajax版本<!DOCTYPE html><html><head><meta charset="utf-8"><title>ajax原生版本</title><script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script></head><body><div id="div1"><h2>使用 jQuery AJAX 修改文本内容</h2></div><button>获取其他内容</button><script>$(document).ready(function(){ $("button").click(function(){ var xhr = new XMLHttpRequest() xhr.onreadystatechange = function(){ if(xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 304)){ var results = xhr.responseText $("#div1").html(results); } } xhr.open('get', 'demo_test.txt',true) xhr.send() });});</script></body></html>// promise版本<!DOCTYPE html><html><head><meta charset="utf-8"><title>promise版本</title><script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script></head><body><div id="div1"><h2>使用 jQuery AJAX 修改文本内容</h2></div><button>获取其他内容</button><script>$(document).ready(function(){ $("button").click(function(){ function ajaxPromise(param){ return new Promise((resovle, reject) => { var xhr = new XMLHttpRequest() xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200 || xhr .status === 304) { var result = xhr.responseText; resovle(result); }else{ var error = xhr.responseText; reject(error); } } } xhr.open(param.type, param.url, true); xhr.send(); }) } var p = ajaxPromise({ url:"demo_test.txt", type: "get" }) p.then(function(value){ $("#div1").html(value); }) });});</script></body></html> 一个错误的Promise实现123456789101112131415161718192021222324252627282930313233343536373839// new Promise(function(resolve,reject){})// myPromise.jsfunction myPromise(fn){ let status = 'waiting' this.successFnList = [] this.failFnList = [] let resolveFn = (value) => { status = 'fulfilled' for(let i = 0; i < this.successFnList.length; i++){ let successFn = this.successFnList[i] successFn.call(undefined,value) } } let rejectFn = (reason) => { status = 'rejected' for(let i = 0; i < this.failFnList.length; i++){ let failFn = this.failFnList[i] failFn.call(undefined,reason) } } fn.call(undefined,resolveFn,rejectFn)}myPromise.prototype.then = function(success,fail){ success && this.successFnList.push(success) fail && this.failFnList.push(fail)}// promise使用let p = new myPromise(function(resolve,reject){ setTimeout(function(){ resolve('big') },1000)})p.then(function(data){ console.log('fn1: ' + data)},function(error){ console.log('fn2: ' + error)})