同步+异步 与promise的原理解析
什么是同步?什么是异步?
同步:百度的名词解释是: 同步指两个或两个以上随时间变化的量在变化过程中保持一定的相对关系。
例如:你去饭店去吃饭。当你叫服务员点餐时,服务员正在别的桌服务,这时你要等待服务员,把别人的事情处理完成以后,才可以到你这服务。不能同时进行。
总结:就是一个任务完成之后,才能执行下一个任务。
异步:执行一个任务的同时,中间去执行其它的事件,最终在回来执行这个任务,不连续。
node最大的特点就是支持异步。
异步 缺点:不支持 try/catch
此时 ,做过项目的的开发者, 估计会遇到类似的问题,要 要用AJAx 拉去 一个id ,再根据id 去拉去某某数据。
代码可能会这样写。
$.ajax({ data:data, url:url, success:function(obj){ var id = obj.id; $.ajax({ data:{id:id}, url:url, success:function(){ } }) } })
首先先看一下最简单的例子,、读文件。 读到文件后才去写。 其中function就是一个callback
1、callback 文件读时。注意路径。
let fs = require("fs"); fs.readFile('./m2.promise/1.txt','utf8',function(err,data){ console.log(data); fs.readFile(data,'utf8',function(err,data){ console.log(data); }) })
//上面是两个文件有关系,
上面是两个文件有关系,现在看并行,现在问题来???无法在
同一时刻合并两个结事, 异步不支持return
fs.readFile('./m2.promise/1.txt','utf8',function(err,data){ console.log(data); }) fs.readFile('./m2.promise/2.txt','utf8',function(err,data){ console.log(data); })
为了解决上面的问题。 此时有一个 名词:“高阶函数”: 函数可以作为 【参数 、函数 、返回值】。满中其中一项,我们都叫 高阶函数。
先来看一个 下面的 两个 函数的 写法。
// 1). 批量生成函数 function isType (type){ //偏函数 return function(content){ return Object.prototype.toString.call(content) === `[object ${type}]`; } } let isArray = isType("Array"); console.log(isArray("kkkk")); //、、2) 预置函数做为 参数, loadsh _.after; function after (times,callback){ return function(){ if(--times == 0){ callback(); } } } let eat = after(3,function(){ console.log("可以了了") }) eat(); eat(); eat();
预置 函数的用法。
例子:需求,当都读到两个文件时,才输出。
let fs = require("fs"); function after (times,callback){ //可以缓存函数,当达到条件时,才执行 let arr = []; return function(data){ arr.push(data); if(--times === 0){ //都拿到后再输出 callback(arr) } } } let out = after (2,function(arr){ console.log(arr); }) fs.readFile("./m2.promise/1.txt","utf8",function(err,data){ // console.log(data); out(data); }) fs.readFile("./m2.promise/1.txt","utf8",function(err,data){ out(data); })
// promise 解决了回调地狱的问题,不会导致难以维护 then
// 解决同步异步的返回结果,按照顺序
上一个简易版的promise 源码解析。
里面 exector 是一个执行器, 执行两个函数 resove 成功函数, , reject 失败函数。
如果成功了,就不走失败
如果失败了,就不走成功。
function Promise(executor){ //executor执行器 let self = this; self.status = 'pending'; //等待态 self.value = undefined; // 表示当前成功的值 self.reason = undefined; // 表示是失败的值 function resolve(value){ // 成功的方法 if(self.status === 'pending'){ self.status = 'resolved'; self.value = value; } } function reject(reason){ //失败的方法 if(self.status === 'pending'){ self.status = 'rejected'; self.reason = reason; } } executor(resolve,reject); } Promise.prototype.then = function(onFufiled,onRejected){ let self = this; if(self.status === 'resolved'){ onFufiled(self.value); } if(self.status === 'rejected'){ onRejected(self.reason); } } module.exports = Promise;
使用
let Promise = require('./m2.Promise'); let p = new Promise(function (resolve, reject) { resolve('zfpx') }); p.then(function(data){ console.log("data",data) },function(err){ console.log('err',err) })
//2.链式调用 jquery,jquery能实现链式调用靠的就是返回this,promise不能返回this,promise实现链式调用靠的是返回一个新的promise。调用then时要 返回一个新的promise
3 如果then中无论是成功的回调还是失败的回调只要返回了结果就会走下一个then中的成功,如果有错误走下一个then的失败
{
/ 当成功或者失败执行时有异常那么返回的promise应该处于失败状态
} 4.如果第一个promise返回一个普通值,会进到下一次then的成功的回调,
//如果第一个promise返回了一个promise,需要等待返回的promise执行后的结果传递给下一次then中
先看一下promise的流程图
function Promise(executor) { // executor是一个执行函数 let self = this; self.status = 'pending'; self.value = undefined; // 默认成功的值 self.reason = undefined; // 默认失败的原因 self.onResolvedCallbacks = []; // 存放then成功的回调 self.onRejectedCallbacks = []; // 存放then失败的回调 function resolve(value) { // 成功状态 if (self.status === 'pending') { self.status = 'resolved'; self.value = value; self.onResolvedCallbacks.forEach(function (fn) { fn(); }); } } function reject(reason) { // 失败状态 if (self.status === 'pending') { self.status = 'rejected'; self.reason = reason; self.onRejectedCallbacks.forEach(function (fn) { fn(); }) } } try { executor(resolve, reject) } catch (e) { // 捕获的时候发生异常,就直接失败了 reject(e); } } function resolvePromise(promise2, x, resolve, reject) { // 有可能这里返回的x是别人的promise // 尽可能允许其他乱写 if (promise2 === x) { //这里应该报一个类型错误,有问题 return reject(new TypeError('循环引用了')) } // 看x是不是一个promise,promise应该是一个对象 let called; // 表示是否调用过成功或者失败 if (x !== null && (typeof x === 'object' || typeof x === 'function')) { // 可能是promise {},看这个对象中是否有then方法,如果有then我就认为他是promise了 try { // {then:1} let then = x.then; if (typeof then === 'function') { // 成功 then.call(x, function (y) { if (called) return called = true // y可能还是一个promise,在去解析直到返回的是一个普通值 resolvePromise(promise2, y, resolve, reject) }, function (err) { //失败 if (called) return called = true reject(err); }) } else { resolve(x) } } catch (e) { if (called) return called = true; reject(e); } } else { // 说明是一个普通值1 resolve(x); // 表示成功了 } } Promise.prototype.then = function (onFulfilled, onRjected) { //成功和失败默认不穿给一个函数 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) { return value; } onRjected = typeof onRjected === 'function' ? onRjected : function (err) { throw err; } let self = this; let promise2; //返回的promise if (self.status === 'resolved') { promise2 = new Promise(function (resolve, reject) { // 当成功或者失败执行时有异常那么返回的promise应该处于失败状态 // x可能是一个promise 也有可能是一个普通的值 setTimeout(function () { try { let x = onFulfilled(self.value); // x可能是别人promise,写一个方法统一处理 resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }) }) } if (self.status === 'rejected') { promise2 = new Promise(function (resolve, reject) { setTimeout(function () { try { let x = onRjected(self.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }) }) } // 当调用then时可能没成功 也没失败 if (self.status === 'pending') { promise2 = new Promise(function (resolve, reject) { // 此时没有resolve 也没有reject self.onResolvedCallbacks.push(function () { setTimeout(function () { try { let x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e) } }) }); self.onRejectedCallbacks.push(function () { setTimeout(function () { try { let x = onRjected(self.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }) }); }) } return promise2; } // 捕获错误的方法 Promise.prototype.catch = function (callback) { return this.then(null, callback) } // 解析全部方法 // let arr = []; // arr[1] = 100; // console.log(arr.length) Promise.all = function (promises) { //promises是一个promise的数组 return new Promise(function (resolve, reject) { let arr = []; //arr是最终返回值的结果 let i = 0; // 表示成功了多少次 function processData(index, y) { arr[index] = y; if (++i === promises.length) { resolve(arr); } } for (let i = 0; i < promises.length; i++) { promises[i].then(function (y) { processData(i, y) }, reject) } }) } // 只要有一个promise成功了 就算成功。如果第一个失败了就失败了 Promise.race = function (promises) { return new Promise(function (resolve, reject) { for (var i = 0; i < promises.length; i++) { promises[i].then(resolve,reject) } }) } // 生成一个成功的promise Promise.resolve = function(value){ return new Promise(function(resolve,reject){ resolve(value); }) } // 生成一个失败的promise Promise.reject = function(reason){ return new Promise(function(resolve,reject){ reject(reason); }) } Promise.defer = Promise.deferred = function () { let dfd = {}; dfd.promise = new Promise(function (resolve, reject) { dfd.resolve = resolve; dfd.reject = reject; }); return dfd } // mjs module.exports = Promise;
proimise 主函数的流程图
then