本文讲述了异步流程的演变过程。那么是什么是异步编程呢: 简单来说就是执行一个指令不会立刻返回结果而执行下一个任务,而是等到特定的事件触发后,才能获得结果。javascript
咱们知道 javascript 运行在浏览器中,以 Google 浏览器为例子, v8 引擎,包含 内存堆: 这是内存分配发生的地方。 调用栈: 这是你代码执行的地方。html
运行一个函数时,解析器把该函数添加到栈中而且执行这个函数。
Web APIs: DOM、AJAX、Timeout(setTimeout)
js是一门单线程的语言, 这意味这它只有一个调用栈。
当咱们堆栈执行的函数须要大量时间时,浏览器会中止响应,幸运的是咱们有异步回调。
javaScript引擎 运行在宿主环境中(浏览器或者 node),
CallbackQueue and Event Loop
事件循环和回调队列
调用栈和回调队列,当栈为空时,它会调取出队列中的第一个事件,放到调用栈中执行;
常见的 macro-task(这个队列也被叫作 task queue) 好比: setTimeout、setInterval、 setImmediate、script(总体代码)、 I/O 操做、UI 渲染等。
常见的 micro-task 好比: process.nextTick、Promise、Object.observe、MutationObserver 等。
promise 永远会在队列尾部添加微观任务
为何Promise的代码(microtask)会比setTimeout的代码(macrotask)更优先执行,由于它太机智了,居然会插队!
复制代码
一双能敲代码的手、一台能执行代码的电脑。 须要预先引入的库java
const fs = require('fs')
const co = require('co')
const util = require('util')
复制代码
第一阶段:回调函数node
function readFile(cb) { fs.readFile('./package.json', (err, data) => { if (err) return cb(err) cb(null, data) }) } readFile((err, data) => { if (!err) { data = JSON.parse(data) console.log(data.name) } }) 复制代码
回调函数的弊端:jquery
采用了事件驱动模型,任务的执行不取决与代码的顺序,取决于某个事件是否发生。编程
function f1() { setTimeout(function() { // f1的任务代码 f1.trigger('done'); }, 1000); } 复制代码
假定咱们存在一个任务中心,当某个事件完成以后,咱们就发射状态信号,调度中心能够通知订阅了该状态信号的其余任务。这个也称为观察者模式。json
jQuery.subscribe("done", f2); function f1(){ setTimeout(function () { // f1的任务代码 jQuery.publish("done"); }, 1000); } 当f1 执行完成后, 向信号中心"jquery"发布"done"信号,从而引起f2的执行。 复制代码
第二阶段:Promisepromise
定义阶段:promise(resolve, reject)分别成功或者失败时处理什么。浏览器
调用阶段:经过then函数实现,成功就执行resolve,它会将reslove的值传递给最近的then函数,做为then函数的参数。若是出错reject,那么交给catch来捕获异常markdown
promise的要点以下:
将回调函数中的结果延后到 then 函数里处理或交给全局异常处理
咱们约定将每一个函数的返回值都得是 promise 对象。 只要是 promise 对象, 就能够控制状态并支持 then 方法,将无限个 promise 对象连接在一块儿。
hello('xx.html').then(log).then(function() { return world('./xxx.js').then(log) }).catch(err => { console.log(err) }) 复制代码
每一个 promise 对象都有 then 方法, 也就是说then方法是定义在原型对象promise.prototype上的, 它的做用是为 promise 实例添加状态改变时的回调函数
Promise.prototype.then() = function (success, fail) { this.done(success) this.fail(fail) return this } 复制代码
通常状况下,只传 success 回调函数便可,fail函数可选,使用catch来捕获函数异常比经过fail函数进行处理更加可控。
const requireDirectory = require(require-directory ) module.export = requireDirectory(module) function readFileAsync(path) { return new Promise((resolve, reject) => { fs.readFile(path, (err, data) => { if (err) reject(err) else resolve(data) }) }) } readFileAsync('./package.json') .then(data => { data = JSON.parse(data) console.log(data.name) }) .catch(err => { console.log(err) }) 复制代码
咱们来看看下面这个例子:
new Promise(function (resolve) { resolve(1) }).then(function (value) { console.log(value) }) Promise.resolve(1).then(function (value) { console.log(' Promise.resovle' + value) }) var error = new Error('this is a error') 复制代码
new Promise更为强大,Promise.resolve更为便捷
如下是更为便捷的写法
function hello(i){ return Promise.resolve(i) } hello(1).then(function(){ console.log('promise.reslove1=' + value) }) // Promise.resolve返回的是prmise对象,至关于 new Promise(resolve,reject)实例 // Promise.prototype.then()方法的语法以下 p.then(onFulfilled,onRejected); // p.then(function(value)){} p.catch(onRejected) // p.catch(function(reson)) {} 复制代码
//整个promise 还有这种写法 hell('./xx.json').then(function (data) { return new Promise(function (reslove, reject) { console.log('promise ' + data) reslove(data) }) }).then(function (data) { return new Promise(function (reslove, reject) { console.log('promise ' + data) reslove(data) }) }).then(function (data) { return new Promise(function (reslove, reject) { console.log('promise ' + data) reslove(data) }) }).catch(function (err) { console.log(err) }) 复制代码
const PENDING = "pending" const FULFILLED = "fulfilled" const REJECTED = "rejected" function MyPromise(executor){ // executor:这是实例Promise对象时在构造器中传入的参数,通常是一个function(resolve,reject){} let that = this; this.status = PENDING; this.value = undefined; this.reason = undefined; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; function resolve(value){ if(value instanceof Promise) { return value.then(resolve, reject); } // 要确保 onFulfilled 和 onRejected 方法异步执行 setTimeout(() => { // 调用resolve 回调对应onFulfilled函数 if (that.status === PENDING) { // 只能由pedning状态 => fulfilled状态 (避免调用屡次resolve reject) that.status = FULFILLED; that.value = value; that.onFulfilledCallbacks.forEach(cb => cb(that.value)); } }); } function reject(reason){ setTimeout(() => { // 调用reject 回调对应onRejected函数 if (that.status === PENDING) { // 只能由pedning状态 => rejected状态 (避免调用屡次resolve reject) that.status = REJECTED; that.reason = reason; that.onRejectedCallbacks.forEach(cb => cb(that.reason)); } }); } // executor方法可能会抛出异常,须要捕获 try { executor(resolve, reject); } catch (e) { reject(e); } } MyPromise.prototype.then = function(onFulfilled, onRejected) { //获取下this let self = this; if(this.status === FULFILLED){ onFulfilled(self.value) } if(this.status === REJECTED){ onRejected(self.value) } //异步时处理 if(this.status === PENDING){ //保存回调函数 this.onFulfilledCallbacks.push(()=>{ onFulfilled(self.value) }); this.onRejectedCallbacks.push(()=>{ onRejected(self.reason) }) } }; var mp = new MyPromise((resolve, reject) => { console.log(11111); setTimeout(() => { resolve(22222); console.log(3333); }, 1000); }); mp.then(x => { console.log(x); console.log('4444') }, (err) => { console.log('err2', err); }) 复制代码
上述代码就是一个简单的promise了,可是还有两点问题没有解决1.链式调用 2.不传值时。 咱们改造下
MyPromise.prototype.then = function(onFulfilled, onRejected) { //获取下this let that = this; //链式调用 在建立一个promise let promsie2 = null; //解决onFulfilled、onRejected没有传值的问题 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : y => y onRejected = typeof onRejected === 'function' ? onRejected : err => {throw err} if (that.status === FULFILLED) { // 成功态 return newPromise = new MyPromise((resolve, reject) => { setTimeout(() => { try{ let x = onFulfilled(that.value); resolvePromise(newPromise, x, resolve, reject); // 新的promise resolve 上一个onFulfilled的返回值 } catch(e) { reject(e); // 捕获前面onFulfilled中抛出的异常 then(onFulfilled, onRejected); } }); }) } if (that.status === REJECTED) { // 失败态 return newPromise = new MyPromise((resolve, reject) => { setTimeout(() => { try { let x = onRejected(that.reason); resolvePromise(newPromise, x, resolve, reject); } catch(e) { reject(e); } }); }); } if (that.status === PENDING) { // 等待态 // 将onFulfilled/onRejected收集暂存到集合中 return newPromise = new MyPromise((resolve, reject) => { that.onFulfilledCallbacks.push((value) => { try { let x = onFulfilled(value); resolvePromise(newPromise, x, resolve, reject); } catch(e) { reject(e); } }); that.onRejectedCallbacks.push((reason) => { try { let x = onRejected(reason); resolvePromise(newPromise, x, resolve, reject); } catch(e) { reject(e); } }); }); } }) }; 复制代码
resolvePromsie 是什么呢: Promise A+ 2.27规范
/** * resolve中的值几种状况: * 1.普通值 * 2.promise对象 * 3.thenable对象/函数 */ /** * 对resolve 进行改造加强 针对resolve中不一样值状况 进行处理 * @param {promise} promise2 promise1.then方法返回的新的promise对象 * @param {[type]} x promise1中onFulfilled的返回值 * @param {[type]} resolve promise2的resolve方法 * @param {[type]} reject promise2的reject方法 */ function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { // 若是从onFulfilled中返回的x 就是promise2 就会致使循环引用报错 return reject(new TypeError('循环引用')); } let called = false; // 避免屡次调用 // 若是x是一个promise对象 (该判断和下面 判断是否是thenable对象重复 因此无关紧要) if (x instanceof Promise) { // 得到它的终值 继续resolve if (x.status === PENDING) { // 若是为等待态需等待直至 x 被执行或拒绝 并解析y值 x.then(y => { resolvePromise(promise2, y, resolve, reject); }, reason => { reject(reason); }); } else { // 若是 x 已经处于执行态/拒绝态(值已经被解析为普通值),用相同的值执行传递下去 promise x.then(resolve, reject); } // 若是 x 为对象或者函数 } else if (x != null && ((typeof x === 'object') || (typeof x === 'function'))) { try { // 是不是thenable对象(具备then方法的对象/函数) let then = x.then; if (typeof then === 'function') { then.call(x, y => { if(called) return; called = true; resolvePromise(promise2, y, resolve, reject); }, reason => { if(called) return; called = true; reject(reason); }) } else { // 说明是一个普通对象/函数 resolve(x); } } catch(e) { if(called) return; called = true; reject(e); } } else { resolve(x); } } 复制代码
测试代码
var p1 = new MyPromise(function (resolve) { setTimeout(function () { resolve(1); }, 1000); }) p1.then(function (val) { console.log(val) var p3 = new MyPromise(function (resolve) { setTimeout(function () { resolve(val + 1); }, 1000); }); return p3; }).then(function (val) { console.log(val); var p4 = new MyPromise(function (resolve) { setTimeout(function () { resolve(val + 1); }, 1000); }); return p4 }).then(function (val){ console.log(val); var p4 = new MyPromise(function (resolve) { setTimeout(function () { resolve(val + 1); }, 1000); }); }); 复制代码
增长Promise.resolve、catch、race 方法
// 用于promise方法链时 捕获前面onFulfilled/onRejected抛出的异常 MyPromise.catch = function(onRejected) { return this.then(null, onRejected); } MyPromise.resolve = function (value) { return new Promise(resolve => { resolve(value); }); } MyPromise.race = function(promises) { return new Promise((resolve, reject) => { promises.forEach((promise, index) => { promise.then(resolve, reject); }); }); } 复制代码