建立一个 readFile.js,读取三个文件abc的内容并输出到控制台ajax
var fs = require('fs') fs.readFile('./a.txt','utf-8',function (err,data) { if(err) throw err //js语法,抛出异常,阻止程序执行,把错误打印到控制台
console.log(data) //将a.txt内容输出到控制台
}) fs.readFile('./b.txt','utf-8',function (err,data) { if(err) throw err console.log(data) }) fs.readFile('./c.txt','utf-8',function (err,data) { if(err) throw err console.log(data) })
通常来讲文件内容少的会先输出,但不必定,因为读取文件是异步操做,因此没法保证abc的输出顺序编程
若想abc按顺序输出,就须要将代码嵌套promise
var fs = require('fs') fs.readFile('./a.txt','utf-8',function (err,data) { if(err) throw err console.log(data) //打印a.txt后再去读取b.txt
fs.readFile('./b.txt','utf-8',function (err,data) { if(err) throw err console.log(data) //打印b.txt后再去读取c.txt
fs.readFile('./c.txt','utf-8',function (err,data) { if(err) throw err console.log(data) }) }) })
像这样,在异步编程中,造成了回调函数嵌套,嵌套过多时被称为回调地狱(callback hell),此方式虽然能让异步操做按顺序执行,但十分不利于阅读和维护浏览器
为了解决回调地狱嵌套编码方式带来的问题,ES6 新增了一个 API 叫 Promise,是一个构造函数异步
Promise上有两个函数叫resolve(成功后的回调函数)和reject(失败后的回调函数)mongoose
Promise原型里有一个then方法,因此只要是Promise建立的实例均可访问then方法异步编程
Promise 容器存在一个异步任务,任务只有三种状态:Pending 为正在执行,Resolve 为已解决,Reiected 为失败函数
示例ui
var fs = require('fs') //Promise容器一旦建立就开始执行里面的代码
var p = new Promise(function (resolve,reject) { fs.readFile('./a.txt','utf-8',function (err,data) { if(err){ reject(err) //把容器的Pending状态变为Rejected
}else{ resolve(data) //把容器的Pending状态改成Resolve
} }) }) //如何获取容器成功和失败的数据,就要用到p实例对象的then方法
//then方法接收的第一个function就是容器中的resolved,第二个function是reject
//两个function的参数就是上面容器resolve和reject传来的data和err.若resolve(123),则这里data就是123
p.then(function (data) { console.log(data)
},function (err) { consoel.log('文件读取失败',err) })
Promise容器的建立不是异步的,但内部每每传入异步任务编码
封装 Promise 版本的 readFile.js
var fs = require('fs') function readFile(filePath) { //将Promise实例对象返回
return new Promise(function (resolve,reject) { fs.readFile(filePath,'utf-8',function (err,data) { if(err){ reject(err) }else{ resolve(data) } }) }) } //由于返回的都是Promise的实例对象,因此可链式调用then
readFile('./a.txt') .then(function (data) { console.log(data) //data就是上面resolve传来的a文件的内容
//而后将新的数据(err和data)经过resolve和reject传递给下一个then的function
return readFile('./b.txt') }) .then(function (data) { console.log(data) return readFile('./c.txt') }) .then(function (data) { console.log(data) })
封装 Promise 版本的 ajax 方法
function get(url) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest() xhr.open('get', url) xhr.send() xhr.onload = function () { resolve(xhr.responseText) //成功则把获取的数据放resolve这个回调函数中
} xhr.onerror = function (err) { reject(err) //失败则把失败信息放reject里
} }) } get('./a.txt') .then(function (data) { console.log(data) return get('./b.txt') }) .then(function (data) { console.log(data) return get('./c.txt') }) .then(function (data) { console.log(data) })
若是前面的promise执行失败,不想让后续的promise操做被终止,可为每一个promise指定失败的回调,而后在失败回调里return新的promise
若是后续的promise执行依赖于前面的,前面的失败了,则后面的没有继续执行下去的意义时,可捕获异常
get('./a.txt') .then(function (data) { console.log(data) return get('./b.txt') }) .then(function (data) { console.log(data) return get('./c.txt') }) .then(function (data) { console.log(data) }) .catch(function(err){ //上面不要写失败回调
console.log(err.message) })
若是前面有任何的promise执行失败则会当即终止全部promise执行并马上进入catch中
这就是捕获异常的两种方式,根据需求,可选择失败回调或catch
模拟 jQuery 的 get 方法
jq中的ajax()返回的是Promise实例,因此可直接点then()
既能使用 Promise 也可使用回调函数嵌套的方式,只需加多一个回调函数便可
function get(url,callback) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest() xhr.open('get', url) xhr.send() xhr.onload = function () { callback(xhr.responseText) resolve(xhr.responseText) //成功则把获取的数据放resolve这个回调函数中
} xhr.onerror = function (err) { callback(err) reject(err) //失败则把失败信息放reject里
} }) } /*get('./a.txt') .then(function (data) { console.log(data) return get('./b.txt') }) .then(function (data) { console.log(data) return get('./c.txt') }) .then(function (data) { console.log(data) })*/ get('./a.txt',function (data) { console.log(data) get('./b.txt',function (data) { console.log(data) get('./c.txt',function (data) { console.log(data) }) }) })
浏览器、Node、mongoose全部 API 都支持 Promise