今天我想说说说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
由上面示例能够看到若是是一个异步操做的代码,一般,咱们就须要为它指定回调函数,例如上面的代码回调函数就是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等各类实例方法和静态方法,不过上面的用法时最常常见到的,最基础的。服务器