js異步操做與promise對象使用

今天我想說說說promise對象,說到這個對象就不能不提提異步操做,那麼什麼是異步操做,什麼又是同步操做?javascript

同步與異步操做區別

同步操做的意思是在咱們執行某個耗時比較長的操做的時候,下面的代碼就會等待上面的代碼執行完畢而後執行。說白了代碼是順序往下執行,某些操做執行的時間順序和代碼所在的行的順序是相同的。請看下面獲取一個txt文件的例子。
同步程序示例
首先,咱們利用node先搭建一個服務器環境,默認獲取1.html靜態文件。代碼以下:css

let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
http.createServer((req, res) => {
    var pathname = __dirname + url.parse(req.url).pathname;
    if (path.extname(pathname) === "") {
        pathname += "/";

    }
    if (pathname.charAt(pathname.length - 1) === "/") {
        pathname += '1.html'
    }
    fs.exists(pathname, exists => {
        if (exists) {
            switch (path.extname(pathname)) {
                case ".html":
                    res.writeHead(200, { 'Content-type': "text/html" });
                    break;
                case ".js":
                    res.writeHead(200, { 'Content-type': "text/javascript" });
                    break;
                case ".jpg":
                    res.writeHead(200, { 'Content-type': "image/jpeg" });
                    break;
                case ".png":
                    res.writeHead(200, { 'Content-type': "image/png" });
                case ".txt":
                    res.writeHead(200, { 'Content-type': "text/plain" });
                    break;
                case ".css":
                    res.writeHead(200, { 'Content-type': "text/css" });
                    break;
                default:
                    ead
                    res.writHead(200, { 'Content-type': "application/octet-stream" })

            }
            fs.readFile(pathname, (err, data) => {
                if (err) {
                    console.log('read file error');
                } else
                    res.end(data);
            })
        }
    })
}).listen(3000);
console.log('server is runing...')

咱們要從服務器用ajax獲取txt文本數據。而後從客戶端獲取數據,若是這個操做是一個同步操做。以下所示
客戶端獲取數據代碼html

function showTxt(txt) {
            console.log(txt);
        }

         function getDocuments(url, cb) {
            let xhr = new XMLHttpRequest();
             xhr.open("GET", url,false);
             xhr.send();、
              cb(xhr.responseText);

                   }
        getDocuments('1.txt', showTxt);
        console.log("我是獲取文件以後執行的代碼");

結果以下:
圖片描述
等這個獲取文件這個操做執行完後,就會順序執行接下來的代碼。
這樣的操做有什麼問題呢?若是這個獲取文件的代碼耗時比較長,咱們的程序就會卡死,下面的代碼就不會執行下去,必須等獲取文件代碼執行完畢,解決問題的方法就是異步獲取文件。那麼什麼是異步操做呢?說白了就是把獲取文件的操做掛到另一個線程,先執行後面的代碼,上面的獲取文件代碼不會阻塞下面代碼的運行。這兩個操做是同時進行的。在之前,一般,若是是異步獲取數據的,那麼執行這個費時的獲取數據操做時,會指定一個回調函數,當獲取文件成功時觸發處理結果的回調函數。在這個過程當中,下面其餘的代碼會同時進行。把剛纔獲取文件的代碼改爲異步,請看下面代碼。
異步獲取數據程序示例java

function showTxt(txt) {
            console.log(txt);
        }

        function getDocuments(url, cb) {
            let xhr = new XMLHttpRequest();
            xhr.open("GET", url);
            xhr.send();


            xhr.onreadystatechange = () => {
                if (xhr.status === 200 && xhr.readyState == 4) {
                    cb(xhr.responseText);

                } else if (xhr.readyState === 4 && xhr.status !== 200) {
                    console.log(`${xhr.status}get error`);
                }
            };
        }
        getDocuments('1.txt', showTxt);
        console.log("我是獲取文件後執行的代碼");
![圖片描述][2]

能夠看出先執行了下面的代碼而後執行了ajax獲取文件回調函數裏面的代碼,證實了下面的其餘操做的代碼會與獲取文件操做同時執行。這就是異步操做與同步操做的區別node

promise對象有什麼用處?

由上面示例能夠看到若是是一個異步操做的代碼,一般,咱們就須要爲它指定回調函數,例如上面的代碼回調函數就是onreadystatechange當它的狀態碼變成4,收到服務器響應,咱們拿到數據後再執行下步操做,先把它掛起來,讓下面的的代碼運行。可是若是因果關係變得複雜,回調事件變得不少,咱們的代碼就會變得十分像一個向右的金字塔結構不利於閱讀。
promise對象巧妙的解決了這個問題,把回調函數變成了鏈式調用,更加符合代碼書寫習慣。那麼如何使用它呢?ajax

請看下面例子

function getTxt(url) {
            let p = new Promise((resolve, reject) => {
                let xhr = new XMLHttpRequest();
                xhr.open("GET", url);
                xhr.send();
                xhr.onreadystatechange = () => {
                    if (xhr.readyState !== 4) {
                        return;
                    }

                    if (xhr.status === 200) {
                        resolve(xhr.responseText);
                    } else {
                        reject(`${xhr.status}get error`);
                    }


                }


            });
            return p;
        }

        getTxt('1.txt').then(showTxt).catch((error) => {
            console.log(error);
        });
        console.log('我是寫在異步操做以後的操做')

總結
經過控制檯打印的內容能夠看出,跟使用回調函數在結果上並無什麼異同。可是代碼結構更加清晰化,而且能夠catch到錯誤信息。
1.先new 一個promise對象,而後給它的參數傳遞一個回調函數進去,回調函數裏面有兩個參數resolve,reject都是函數。
2.resolve函數是把異步狀態變成成功,能夠把異步結果做爲它的參數傳遞到then的回調函數參數中,而then方法會在promise狀態成功時候調用;3.reject函數能夠把promise狀態變成失敗,當異步請求狀態失敗時調用,能夠傳遞出去錯誤信息,這個會觸發promise對象上的catch方法,經過promise對象的catch方法的回調函數的參數捕獲該錯誤信息。最後返回該promise對象實現鏈式調用。這就是promise對象的基本用法。promise

4.固然它還有all, race,resolve,reject等各類實例方法和靜態方法,不過上面的用法時最常常見到的,最基礎的。服務器

相關文章
相關標籤/搜索