1. callback hell 回调地狱
1.1 没有顺序的读取 a b c 三个文件
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
| const fs = require('fs')
fs.readFile('./a.txt', 'utf8', function (err, data) { if (err) {
throw err } console.log(data); }) fs.readFile('./b.txt', 'utf8', function (err, data) { if (err) {
throw err } console.log(data); }) fs.readFile('./c.txt', 'utf8', function (err, data) { if (err) {
throw err } console.log(data); })
|
1 2 3 4 5 6 7 8 9 10 11 12
| PS F:\nodejs\Node_test> node .\13.回调地狱.js hello aaaa hello bbbb hello cccc PS F:\nodejs\Node_test> node .\13.回调地狱.js hello aaaa hello cccc hello bbbb PS F:\nodejs\Node_test> node .\13.回调地狱.js hello aaaa hello cccc hello bbbb
|
1.2 想要有顺序的分别 读取 a b c 三个文件
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
| const fs = require('fs')
fs.readFile('./a.txt', 'utf8', function (err, data) { if (err) {
throw err } console.log(data); fs.readFile('./b.txt', 'utf8', function (err, data) { if (err) {
throw err } console.log(data); fs.readFile('./c.txt', 'utf8', function (err, data) { if (err) {
throw err } console.log(data); }) })
})
|
1 2 3 4 5 6 7 8 9 10 11 12
| PS F:\nodejs\Node_test> node .\13.回调地狱.js hello aaaa hello bbbb hello cccc PS F:\nodejs\Node_test> node .\13.回调地狱.js hello aaaa hello bbbb hello cccc PS F:\nodejs\Node_test> node .\13.回调地狱.js hello aaaa hello bbbb hello cccc
|
想要有顺序的读取异步操作中的文件 就需要回调函数嵌套,但这样的代码 看起来很乱且维护性低
为了解决这样的问题,(回调地狱嵌套) 这时我们就需要用ES6中的API promise
Promise
参考文档 promise 阮一峰 和 promise MDN
为什么需要用promise?
我个人理解有三点:
- 在使用ajax调用成功和失败方法时,命名不够规范。
- 容易出现回调地狱
- 很难进行错误处理
- 解决异步
promise是什么?
打印出来看看:
很显然,promise是一个构造函数,它除了自身有 resolve 、 reject、 all 、race方法等,原型上还有then 、catch 等我们最常用到的方法。 所以我们 new promise 里面是肯定有 then 、 catch 方法的。
如何创建一个promise
1 2 3 4 5 6 7 8 9 10 11 12
| function runAsync() { const p = new Promise((resolve, reject) => { setTimeout(() => { console.log('执行成功'); resolve('数据') }, 1000) }) return p }
runAsync()
|
其中Promise构造函数接受一个参数,就是函数。并且会传入俩个参数:resolve,reject 。 分别表示异步操作执行成功后的回调函数和执行失败后的回调函数。
我们将包装一个函数,把promise放在里面并返回它, 这样做的意义在于我们可以使用promise原型上的then,catch方法
1 2 3 4
| runAsync().then(function(data){ console.log(data); });
|
效果展示
以上就是Promise的作用了,简单的说,就是能把原来的回调写法分离出来,在异步操作执行完后,用链式操作的形式执行回调函数。
promise.all 用法
all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完毕后才执行回调。
请看下面例子:
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
| function runAsync1() { const p = new Promise((resolve, reject) => { setTimeout(() => { console.log('执行成功'); resolve('数据1') }, 1000) }) return p }
function runAsync2() { const p = new Promise((resolve, reject) => { setTimeout(() => { console.log('执行成功'); resolve('数据2') }, 1500) }) return p }
function runAsync3() { const p = new Promise((resolve, reject) => { setTimeout(() => { console.log('执行成功'); resolve('数据3') }, 2000) }) return p }
Promise .all([ runAsync1(), runAsync2(), runAsync3() ]) .then(result => console.log(result))
|
我们用Promise.all 来执行, 并且接受三个数组,里面的值都返回的是Promise对象,然后这三个异步操作并行执行,等它们都执行完毕后,数据才会在then方法里面。即all方法会把所有异步操作的结果放在一个属猪中再传给then。
Promise.race 用法
用法和Promise.all 一样,只不过all方法是谁跑得慢,就以谁为准执行回调, 而race方法就是谁跑得快,就以谁为准执行回调
将上面展示的代码 的all方法换成race看看是什么效果
1 2 3 4 5 6 7
| Promise .race([ runAsync1(), runAsync2(), runAsync3() ]) .then(result => console.log(result))
|
瞧!他会去优先输出最快(1s)的runAsync1函数的数据,
原因是因为异步处理问题,runAsync1函数的数据并不会等待上面的Promise执行完在开始执行,所以由于时间延迟,优先输出‘数据1’。