回調地獄的產生
無法保證順序的代碼:
var fs = require('fs')
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('讀取失敗')
// 拋出異常
// 1. 阻止程序的執行
// 2. 把錯誤消息打印到控制檯
throw err
}
console.log(data)
})
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
})
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
})
由於是readFile是異步的,無法保證讀取文件內容的輸出是一步一步來的
如何保證順序呢?通過回調的方式保證其順序
var fs = require('fs')
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
})
})
})
這裏只有三個異步函數,如果多個,會產生回調地獄。
一個任務依賴於一個異步任務執行完之後,這裏必須進行嵌套才能解決。
問題:嵌套的太深,代碼不好看,很難維護
怎麼去解決這個問題呢?在ES6中新增了一個API——Promise
Promise是如何解決回調地獄的
promise是一個容器,裏面存放了一個正在執行的任務(pending:正在執行),這個任務執行結束後,可能有兩個狀態,resolved(完成)和 rejected(失敗),狀態只能是其中的一種
promoise的使用
promise是一個構造函數
//promise容器一旦創建,就開始執行裏面的代碼,容器裏可以放置異步函數,但是promise本身不是異步的
//創建Promise容器,給別人一個承若:I Promise you
var p1 = new Promise(function(resolve,reject){
console.log('hello') //這裏的代碼不是異步的
fs.readFile('./data/a.txt','utf8',function(err,data){
if(err){
//承渃容器中的任務失敗了,把容器的Pending狀態變爲 Rejected
//調用reject就相當於調用了then方法的第二個參數
reject(err)
}else{
//承渃容器中的任務成功了,把容器的Pending狀態變爲 Resolved
//調用resolve就相當於調用了then方法的第一個參數
resolve(data)
}
})
})
//p1就是那個承若,當p1成功了,然後then做指定的操作,then方法接收的第一個function就是容器中的resolved函數
p1
.then(function(data){
console.log(data)
},function(err){
console.log('讀取文件失敗了',err)
})
promise解決回調地獄問題示例
var p1 = new Promise(function(resolve,reject){
fs.readFile('./data/a.txt','utf8',function(err,data){
if(err){
reject(err)
}else{
resolve(data)
}
})
})
var p2 = new Promise(function(resolve,reject){
fs.readFile('./data/b.txt','utf8',function(err,data){
if(err){
reject(err)
}else{
resolve(data)
}
})
})
var p2 = new Promise(function(resolve,reject){
fs.readFile('./data/c.txt','utf8',function(err,data){
if(err){
reject(err)
}else{
resolve(data)
}
})
})
p1
.then(function (data) {
console.log(data)
//當p1讀取成功的時候
//當前函數中的return的結果就可以在後面的then中function
//當你return 123 後面接接收到 123
// return 'hello' 後面就接收到 ’hello'
// 沒有return後面收到的就是undefined
//上面那些return的數據沒什麼卵用
//真正有用的是:我們可以return一個promise對象
//當return一個Promise對象的時候,後續的then中的方法的第一個參數會作爲p2的resolve
return p2
}, function (err) {
console.log('讀取文件失敗了', err)
})
.then(function (data) {
console.log(data)
return p3
})
.then(function (data) {
console.log(data)
console.log('end')
})
封裝promise ——API
var fs = require('fs')
function pReadFile(filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
pReadFile('./data/a.txt')
.then(function (data) {
console.log(data)
return pReadFile('./data/b.txt')
})
.then(function (data) {
console.log(data)
return pReadFile('./data/c.txt')
})
.then(function (data) {
console.log(data)
})
簡單封裝Promise版本的ajax方法
function pGet(url){
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest()
xhr.onLoad = function(){
resolve(xhr.responseText)
}
xhr.onerror = function(err){
reject(err)
}
xhr.open('get',url,true)
xhr.send()
})
}
pGet('http:127.0.0.1/user')
.then(function(data){
console.log(data)
return pGet('http://127.0.0.1/job')
})
.then(function(data){
console.log(data)
})