03、Promise,Vue-cli搭建專案

weixin_34320159發表於2019-01-27

Promise 物件

看看一個例子

function fn1() {
  setTimeout(()=>{
    console.log('fn1')
  }, 1000)
}

function fn2() {
  setTimeout(()=>{
    console.log('fn2')
  }, 1000)
}

function fn3() {
  setTimeout(()=>{
    console.log('fn3')
  }, 1000)
}

對於以上程式碼如何實現: 1秒鐘之後輸出 fn1, 再過疫苗輸出 fn2, 再過1秒輸出 fn3 ?

可如下改裝:

function fn1(callback) {
  setTimeout(()=>{
    console.log('fn1')
    callback()
  }, 1000)
}

function fn2(callback) {
  setTimeout(()=>{
    console.log('fn2')
    callback()
  }, 1000)
}

function fn3() {
  setTimeout(()=>{
    console.log('fn3')
  }, 1000)
}

fn1(function(){
  fn2(function(){
    fn3()
  })
})

回撥地獄!

什麼是 Promise

參考阮一峰 ES6教程

Promise 是一個物件,物件裡儲存一個狀態,這個狀態是可以隨著內部的執行轉化的,為以下三種狀態之一:等待態(Pending)、完成態(Fulfilled)、拒絕態(Rejected)。

一開始,我們先設定好等狀態從 pending 變成 fulfilled 和 rejected 的預案(當成功後我們做什麼,失敗時我們做什麼)。

Promise 啟動之後,當滿足成功的條件時我們讓狀態從 pending 變成 fullfilled (執行 resolve);當滿足失敗的條件,我們讓狀態從 pending 變成 rejected(執行 reject)

Promise 範例

範例1

Promise.prototype.then / Promise.prototype.catch

function getIp() {
  var promise = new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getIp', true)
    xhr.onload = function(){
      var retJson = JSON.parse(xhr.responseText)  // {"ip":"58.100.211.137"}
      resolve(retJson.ip)
    }
    xhr.onerror = function(){
      reject('獲取IP失敗')
    }
    xhr.send()
  })
  return promise
}

function getCityFromIp(ip) {
  var promise = new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true)
    xhr.onload = function(){
      var retJson = JSON.parse(xhr.responseText)  // {"city": "hangzhou","ip": "23.45.12.34"}
      resolve(retJson.city)
    }
    xhr.onerror = function(){
      reject('獲取city失敗')
    }
    xhr.send()
  })
  return promise
}
function getWeatherFromCity(city) {
  var promise = new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getWeatherFromCity?city='+city, true)
    xhr.onload = function(){
      var retJson = JSON.parse(xhr.responseText)   //{"weather": "晴天","city": "beijing"}
      resolve(retJson)
    }
    xhr.onerror = function(){
      reject('獲取天氣失敗')
    }
    xhr.send()
  })
  return promise
}

getIp().then(function(ip){
  return getCityFromIp(ip)
}).then(function(city){
  return getWeatherFromCity(city)
}).then(function(data){
  console.log(data)
}).catch(function(e){
  console.log('出現了錯誤', e)
})

Promise.all

範例2


function getCityFromIp(ip) {
  var promise = new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true)
    xhr.onload = function(){
      var retJson = JSON.parse(xhr.responseText)  // {"city": "hangzhou","ip": "23.45.12.34"}
      resolve(retJson)
    }
    xhr.onerror = function(){
      reject('獲取city失敗')
    }
    xhr.send()
  })
  return promise
}

var p1 = getCityFromIp('10.10.10.1')
var p2 = getCityFromIp('10.10.10.2')
var p3 = getCityFromIp('10.10.10.3')

//Promise.all, 當所有的 Promise 物件都完成後再執行
詳情,評價,購買人群
Promise.all([p1, p2, p3]).then(data=>{
  console.log(data)
})

Pomise.all的使用

Promise.all可以將多個Promise例項包裝成一個新的Promise例項。同時,成功和失敗的返回值是不同的,成功的時候返回的是一個結果陣列,而失敗的時候則返回最先被reject失敗狀態的值。

let p1 = new Promise((resolve, reject) => {
  resolve('成功了')
})

let p2 = new Promise((resolve, reject) => {
  resolve('success')
})

let p3 = Promse.reject('失敗')

Promise.all([p1, p2]).then((result) => {
  console.log(result)               //['成功了', 'success']
}).catch((error) => {
  console.log(error)
})

Promise.all([p1,p3,p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)      // 失敗了,打出 '失敗'
})

Promse.all在處理多個非同步處理時非常有用,比如說一個頁面上需要等兩個或多個ajax的資料回來以後才正常顯示,在此之前只顯示loading圖示。

let wake = (time) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`${time / 1000}秒後醒來`)
    }, time)
  })
}

let p1 = wake(3000)
let p2 = wake(2000)

Promise.all([p1, p2]).then((result) => {
  console.log(result)       // [ '3秒後醒來', '2秒後醒來' ]
}).catch((error) => {
  console.log(error)
})

需要特別注意的是,Promise.all獲得的成功結果的陣列裡面的資料順序和Promise.all接收到的陣列順序是一致的,即p1的結果在前,即便p1的結果獲取的比p2要晚。這帶來了一個絕大的好處:在前端開發請求資料的過程中,偶爾會遇到傳送多個請求並根據請求順序獲取和使用資料的場景,使用Promise.all毫無疑問可以解決這個問題。
二、Promise.race的使用
顧名思義,Promse.race就是賽跑的意思,意思就是說,Promise.race([p1, p2, p3])裡面哪個結果獲得的快,就返回那個結果,不管結果本身是成功狀態還是失敗狀態。

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  },1000)
})

let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('failed')
  }, 500)
})

Promise.race([p1, p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)  // 開啟的是 'failed'
})

//Promise.all, 當所有的 Promise 物件都完成後再執行
Promise.race([p1, p2, p3]).then(data=>{
console.log(data)
})


對於開頭回撥地獄的解決

function fn1() {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
console.log('fn1...')
resolve()
}, 1000)
})
}

function fn2() {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
console.log('fn2...')
resolve()
}, 1000)
})
}

function fn3() {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
console.log('fn3...')
resolve()
}, 1000)
})
}

function onerror() {
console.log('error')
}

fn1().then(fn2).then(fn3).catch(onerror)


---
# 使用腳手架搭建專案

## 安裝

開啟終端,切換到一個經常使用的專案目錄,如

cd ~/projects


全域性安裝 vue-cli

npm install -g vue-cli


使用 vue-cli 建立 基於webpack模板的新專案

vue init webpack vue-evernote-client


![image](http://upload-images.jianshu.io/upload_images/3680331-2d24a6e125a00eb8.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



按回車![image](http://upload-images.jianshu.io/upload_images/3680331-f845ed9be840e3d3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



按回車![image](http://upload-images.jianshu.io/upload_images/3680331-2acdffa3b4572408.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



按回車![image](http://upload-images.jianshu.io/upload_images/3680331-f4d15d222beab92e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



使用預設選項 Runtime + Compile 即可,直接按回車![image](http://upload-images.jianshu.io/upload_images/3680331-9c03ebac148c260f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


輸入 Y,按回車![image](http://upload-images.jianshu.io/upload_images/3680331-808dcaf0fc96a4a8.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



輸入 n,按回車![image](http://upload-images.jianshu.io/upload_images/3680331-09d68e206aa3280b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



輸入 n,按回車![image](http://upload-images.jianshu.io/upload_images/3680331-7ad18f8d05fa766b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



輸入 n,按回車![image](http://upload-images.jianshu.io/upload_images/3680331-3eb0aa018d1fe6e3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


使用預設的 npm 作為包管理工具,直接按回車

等待安裝,安裝完畢後

進入當前專案目錄

cd vue-evernote-client


安裝依賴

npm install


![image](http://upload-images.jianshu.io/upload_images/3680331-b196241e84e1386a.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

啟動server

npm run dev


瀏覽器開啟 [http://localhost:8080](http://localhost:8080/ "null") ,即可看到搭建好的初始介面

![image](http://upload-images.jianshu.io/upload_images/3680331-9adbc38fedef364a.jpg-middle?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

可以使用編輯器開啟 vue-evernote-client 這個目錄,閱讀程式碼,目前我們暫時只需要關注 src 這個目錄即可。

|-- build // 專案構建(webpack)相關程式碼
| |-- build.js // 生產環境構建程式碼
| |-- check-version.js // 檢查node、npm等版本
| |-- dev-client.js // 熱過載相關
| |-- dev-server.js // 構建本地伺服器
| |-- utils.js // 構建工具相關
| |-- webpack.base.conf.js // webpack基礎配置
| |-- webpack.dev.conf.js // webpack開發環境配置
| |-- webpack.prod.conf.js // webpack生產環境配置
|-- config // 專案開發環境配置
| |-- dev.env.js // 開發環境變數
| |-- index.js // 專案一些配置變數
| |-- prod.env.js // 生產環境變數
| |-- test.env.js // 測試環境變數
|-- src // 原始碼目錄
| |-- components // vue公共元件
| |-- apis // 請求介面
| |--utils // 工具庫
| |-- views // 業務元件
| |-- store // vuex的狀態管理
| |-- App.vue // 頁面入口檔案
| |-- main.js // 程式入口檔案,載入各種公共元件
|-- static // 靜態檔案,比如一些圖片,json資料等
| |-- data // 群聊分析得到的資料用於資料視覺化
|-- .babelrc // ES6語法編譯配置
|-- .editorconfig // 定義程式碼格式
|-- .gitignore // git上傳需要忽略的檔案格式
|-- README.md // 專案說明
|-- favicon.ico
|-- index.html // 入口頁面
|-- package.json // 專案基本資訊

相關文章