nodejs中的promise基本操作 1.为什么要使用promise 2.Promise基本使用 3.promise参数resolve和reject 4.解决回调地狱问题 5.catch的使用 6 then-catch-finally 7. Promise.all静态方法的使用

/*
需求:异步的按顺序去读取1.txt、2.txt、3.txt文件的内容
假设 1.txt内容为111 、2.txt内容为222、3.txt内容为333
*/
var  fs = require('fs');、
 fs.readFile('./files/1.txt','utf8',function(err,data){
   if(err){
     throw err;
   }
   console.log(data);
 })

 fs.readFile('./files/1.txt','utf8',function(err,data){
   if(err){
     throw err;
   }
   console.log(data);
 })

 fs.readFile('./files/1.txt','utf8',function(err,data){
   if(err){
     throw err;
   }
   console.log(data);
 })
/*
 结果:111 222 333。(好像满足需求啊)
*/

/* 
问题:上面的代码虽然正常按照顺序读取了文件,因为文件的内容都非常少,io读取耗时少,但当2.txt内容较多时候,2.txt的内容是最后输出的。因为他们都是异步操作,不知道谁先读取完。 这得取决于异步任务IO的耗时。
*/

/*
常规解决办法:
在第一个异步任务读取成功之后再读取第二个异步任务,
第二成功后,在读取第三个异步任务
*/
//读取第一个异步任务
fs.readFile('./files/1.txt','utf8',function(err,data){
  if(err){
    throw err;
  }
  console.log(data);
  //读取第二个异步任务
  fs.readFile('./files/2.txt','utf8',function(err,data){
    console.log(data);
    //读取第三个异步任务
    fs.readFile('./files/3.txt','utf8',function(err,data){
      console.log(data);
    })
  })
})

/* 
结果: 111 222 333 (这必须按照顺序输出的,结果杠杆的)  
*/

/*
问题:
以上按照顺序执行多个异步任务产生的问题:`回调地狱`问题(层层包裹进行回调,代码也不够优雅)
*/

/* 
解决办法:采用es6,提供的promise来解决上述产生的问题。
*/

2.Promise基本使用

promise介绍:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise


//简单说promise就是用来执行异步任务的,可以解决上面所说的回调地狱问题,
//语法:new Promise(function(callback){})
var  fs = require('fs');
var promise = new Promise(function(resolve,reject){
  //这里就是写异步的代码,只要new  Promise操作,就会立刻执行这里的代码
  //两个参数 resolve 异步执行成功的回调函数,reject异步执行失败的回调函数
  fs.readFile('./files/1.txt', 'utf8', function (err, data) {
    if (err) {
      throw err;
    }
    console.log(data);
  })
});
//运行结果:111

3.promise参数resolve和reject

两个参数

  • resolve 异步执行成功的回调函数,
  • reject异步执行失败的回调函数

var fs = require('fs');
var promise = new Promise(function (resolve, reject) {
  //两个参数: resolve 成功的回调函数名  , reject失败的回调函数名
  fs.readFile('./files/111.txt', 'utf8', function (err, data) {
    if (err) {
      //说明失败了,要执行失败的回调函数
      reject(err);
    } else {
      //成功的逻辑
      resolve(data);
    }
    //等价于
    // err ? reject(err) : resolve(data);
  })
});

//new Promise返回的是一个promise对象,
//这个对象有一个方法叫做then,在其原型对象上
//通过这then方法可以指定成功和失败的回调函数
//语法:promise.then(successCallback,errorCallback);
promise.then(function (data) {
  //then第一个函数是成功的回调,参数是resolve(err)中的data
  console.log('成功:' + data); // 若成功,运行结果:成功:111
}, function (err) {
  //then第二个函数是失败的回调函数,参数是reject(err)中的err错误对象
  console.log('失败:' + err);
});

4.解决回调地狱问题


//封装一个异步读取文件的内容的函数
//此函数返回对应异步任务的promise对象
function getFileByPath(path) {
  return new Promise(function (resolve,reject) {
    fs.readFile(path, 'utf8', function (err, data) {
      if(err){
        reject(err);   //失败
      }else{
        resolve(data);    //成功
      }
    })
  });
}

//由于then通过getFileByPath返回的是一个promise对象,所以可以继续.then串联调用(链式调用)
getFileByPath('./files/1.txt')
.then(function(data){
  console.log("成功:"+data);
  return getFileByPath('./files/2.txt');
},function(err){
  console.log("失败:"+err);
  return getFileByPath('./files/2.txt');
}) 
.then(function(data){ 
  console.log("成功:"+data);
  return getFileByPath('./files/3.txt');
},function(err){
  console.log("失败:"+err);
  return getFileByPath('./files/3.txt');
})
.then(function(data){
  console.log("成功:"+data);
},function(err){
  console.log("失败:"+err);
});

注意:上面一定会保证按照.then的顺序去执行异步的代码,
如果某个异步任务有错误则会触发对应then的第二个错误的回调函数。即每个promise对象都有对应的错误回调,对其他的promise不影响。毕竟promise的英文翻译就是保证。

5.catch的使用

catch也是在Promise.prototype原型上定义的。

nodejs中的promise基本操作
1.为什么要使用promise
2.Promise基本使用
3.promise参数resolve和reject
4.解决回调地狱问题
5.catch的使用
6 then-catch-finally
7. Promise.all静态方法的使用

image.png

需求:如果多个promise任务,其中有一个失败了,则终止后面的所有的promise执行

getFileByPath('./files/1.txt')
.then(function(data){
  console.log("成功:"+data);
  return getFileByPath('./files/2.txt');
}) //上面的then通过getFileByPath返回的是一个promise对象,所以可以继续.then串联调用(链式调用)
.then(function(data){ 
  console.log("成功:"+data);
  return getFileByPath('./files/3.txt');
})
.then(function(data){
  console.log("成功:"+data);
})
.catch(function(err){   
  // catch作用: 上面所有的promise如果其中一个有错误,
  //则终止下面所有的promise执行,且直接进入到catch中获取对应promise的异常错误信息
  console.log('catch:'+err);
})

注意:如果在then中定义了错误回调则不会进入到上面的catch中,这是因为promise对象指定了对应的错误处理回调。

6 then-catch-finally


var fs = require('fs');
var promise = new Promise(function (resolve, reject) {
  //两个参数: resolve 成功的回调函数名  , reject失败的回调函数名
  fs.readFile('./files/11.txt', 'utf8', function (err, data) {
    if (err) {
      //说明失败了,要执行失败的回调函数
      reject(err);
    } else {
      //成功的逻辑
      resolve(data);
    }
  })
});

//new Promise返回的是一个promise对象,
//这个对象有一个方法叫做then,在其原型对象上
//通过这then方法可以指定成功和失败的回调函数
//语法:promise.then(successCallback,errorCallback);
promise.then(function (data) {
  //then第一个函数是成功的回调,参数是resolve(err)中的data
  console.log('成功:' + data); // 若成功,运行结果:成功:111
}).catch(function(err){
  //then第二参数错误回调换成这里catch也行,两者选其一
  console.log('err');
}).finally(function(){
  //无论失败成功都会执行
  console.log('完成');
})

7. Promise.all静态方法的使用

参照:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise#%E6%96%B9%E6%B3%95
需求:把所有的promise执行成功的结果保存在一个数组中。。

var promise1 = getFileByPath('./files/1.txt');
var promise2 = getFileByPath('./files/2.txt');
var promise3 = getFileByPath('./files/3.txt');

//执行多个异步任务,
Promise.all([promise3,promise1,promise2]).then(function(data){
  console.log(data); 
},function(err){
  console.log('错误了:'+err);
})
//Promise.all尤其是在一个页面上发起多个ajax请求的时候,如果要同时保证他们成功,则使用Promise.all是最合适不过的了。其中一个失败则也可以在then的第二个回调做失败的逻辑。

若都成功,运行结果:['333','111','22']

注意:Promise.all的成功结果是返回一个数组,且数组中数据的结果顺序与Promise.all数组的传参顺序是一样的。