手写Promise
Promises/A+ 英文原版说明:https://promisesaplus.com/
Promises/A+ 中文翻译:https://juejin.im/post/5b6161e6f265da0f8145fb72
1. Promise解决了什么问题?
以前的异步函数处理是回调函数,如果回到函数参数还是回调函数,如果层级多了,那么就会产生回调地狱问题
异步函数回调地狱问题:
1 2 3 4 5 6 7 8 9
| fs.readdir(source, function (err, files) { if (err) {console.log('报错')} else { files.forEach(function (filename, fileIndex){ if (err) {console.log('报错')} else { } }) } })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| fs.readdir(source, function (err, files) { if (err) { console.log('Error finding files: ' + err) } else { files.forEach(function (filename, fileIndex) { console.log(filename) gm(source + filename).size(function (err, values) { if (err) { console.log('Error identifying file size: ' + err) } else { console.log(filename + ' : ' + values) aspect = (values.width / values.height) widths.forEach(function (width, widthIndex) { height = Math.round(width / aspect) console.log('resizing ' + filename + 'to ' + height + 'x' + height) this.resize(width, height) .write(dest + 'w' + width + '_' + filename, function (err) { if (err) console.log('Error writing file: ' + err) }) }.bind(this)) } }) }) } })
|
回调地狱真的是个问题吗?有没有可能是这个程序员水平不行?
回调可以不地狱,回调没有问题,出现地狱是水平的问题。但是水平差的人就是多,所以妥协了。
回调不地狱:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| fs.readdir(source, (err, files) => { travalFiles = () => { if (err) { return console.log('Error: 找不到目录 ' + err) } files.forEach(gmFile) } gmFile = (filename) => { console.log(filename) gm(source + filename).size(afterGetSize) } afterGetSize = (err, values) => { if (err) return console.log('无法读取文件尺寸: ' + err) console.log(filename + ' : ' + values) aspect = (values.width / values.height) widths.forEach((width, widthIndex) => resize(width, aspect)) } resize = (width, aspect) => { height = Math.round(width / aspect) console.log('将' + filename + '的尺寸变为 ' + width + 'x' + height) this.resize(width, height) .write(dest + 'w' + width + '_' + filename, (err) => err && console.log('Error writing file: ' + err) ) } travalFiles(err, files) })
|
2. Promise有什么优点?
3. 用户怎么用Promise
以前:
1 2 3 4 5
| function 摇色子(fn){ setTimeout(()=>{ const result = Math.floor(Math.random()*6+1) fn(result) } 摇色子(n=>console.log(`摇到了${n}`))
|
现在:
1 2 3 4 5 6 7 8
| function 摇色子(){ setTimeout(()=>{ const result = Math.floor(Math.random()*6+1) resolve(result) },3000) }) } 摇色子().then(n=>console.log(`摇到了${n}`))
|
4. Promise的完整API是什么
- Promise是一个类
- JS里类是一个特殊的函数
- 类属性: length
- 类方法:all / allSettled / race / reject / resolve
- 对象属性: then(重要) / finally / catch
- 对象内部属性:state = pending / fulfilled / rejected
5. Promise 的手写代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| class Promise1 { state = 'pending'; callbacks = []; constructor(fn) { if (typeof fn !== "function") { throw new Error("我只接受函数"); } fn(this.resolve.bind(this), this.reject.bind(this)); } resolve (result) { if (this.state !== "pending") return; this.state = "fulfilled"; setTimeout(() => { this.callbacks.forEach this.callbacks.forEach(handle => { if (typeof handle[0] === "function") { handle[0].call(undefined, result); } }); }) } reject (reason) { if (this.state !== "pending") return; this.state = "rejected"; setTimeout(() => { this.callbacks.forEach(handle => { if (typeof handle[1] === "function") { handle[1].call(undefined, reason); } }); }); }
then (succeed, fail) { const handle = []; if (typeof succeed === "function") { handle[0] = succeed; } if (typeof fail === "function") { handle[1] = fail; } this.callbacks.push(handle); return undefined; } }
function nextTick(fn) { if (process !== undefined && typeof process.nextTick === "function") { return process.nextTick(fn); } else { var counter = 1; var observer = new MutationObserver(fn); var textNode = document.createTextNode(String(counter)); observer.observe(textNode, { characterData: true }); counter = counter + 1; textNode.data = String(counter); } }
|
https://github.com/FrankFang/promise-1/blob/master/src/promise.ts