前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Promise 源码分析

Promise 源码分析

作者头像
用户2356368
发布于 2019-04-03 08:12:52
发布于 2019-04-03 08:12:52
77800
代码可运行
举报
文章被收录于专栏:薄荷前端薄荷前端
运行总次数:0
代码可运行

前言

then/promise项目是基于Promises/A+标准实现的Promise库,从这个项目当中,我们来看Promise的原理是什么,它是如何做到的,从而更加熟悉Promise

分析

从index.js当中知道,它是先引出了./core.js,随后各自执行了其他文件的代码,通过requeire的方法。

我们首先先想一下最基础的promise用法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
new Promise((resolve, reject) =>  {
    resolve(4);

}).then(res => {
    console.log(res); // export 4
});
复制代码

Promise中的标准

标准中规定:

  1. Promise对象初始状态为 Pending,在被 resolvereject 时,状态变为 FulfilledRejected
  2. resolve接收成功的数据,reject接收失败或错误的数据
  3. Promise对象必须有一个 then 方法,且只接受两个可函数参数 onFulfilledonRejected

index.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'use strict';

module.exports = require('./core.js');
require('./done.js');
require('./finally.js');
require('./es6-extensions.js');
require('./node-extensions.js');
require('./synchronous.js');

复制代码

我们先看src/core.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Promise(fn) {
  // 判断 this一定得是object不然就会报错,这个方法一定得要new出来
  if (typeof this !== 'object') {
    throw new TypeError('Promises must be constructed via new');
  }
  // 判断fn 一定得是一个函数
  if (typeof fn !== 'function') {
    throw new TypeError('Promise constructor\'s argument is not a function');
  }
  this._deferredState = 0;
  this._state = 0;
  this._value = null;
  this._deferreds = null;
  if (fn === noop) return;
  // 最终doResolve很关键
  doResolve(fn, this);
}
复制代码

Promise是一个构造方法,开始时,它进行了校验,确保了fn是一个函数,随后对一些变量进行了初始化,最后执行了doResolve()

我们接着看doResolve这个方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Take a potentially misbehaving resolver function and make sure
 * onFulfilled and onRejected are only called once.
 *
 * Makes no guarantees about asynchrony.
 */
// 
// 确保`onFulfilled`和`onRejected`方法只调用一次
// 不保证异步
function doResolve(fn, promise) {
  var done = false;
  var res = tryCallTwo(fn, function (value) {
    // 如果done 为true 则return
    if (done) return;
    done = true;
    // 回调执行 resolve()
    resolve(promise, value);
  }, function (reason) {
    // 如果done 为true 则return
    if (done) return;
    done = true;
    reject(promise, reason);
  });
  // res为truCallTwo()的返回值
  // 如果done没有完成 并且 res 是 `IS_ERROR`的情况下
  // 也会执行reject(),同时让done完成
  if (!done && res === IS_ERROR) {
    done = true;
    reject(promise, LAST_ERROR);
  }
}
复制代码

doResolve最关键的是执行了tryCallTwo方法,这个方法的第二,第三个参数都是回调,当执行回调后,done为true,同时各自会执行resolve()或者reject()方法。最后当tryCallTwo的返回值为IS_ERROR时,也会执行reject()方法。

我们先来看一下tryCallTwo方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
复制代码

fn实际就是Promise初始化时的匿名函数(resolve, reject) => {}ab则代表的是resolve()reject()方法,当我们正常执行完promise函数时,则执行的是resolve则在doResolve中,我们当时执行的第二个参数被回调,如果报错,reject()被执行,则第二个参数被回调。最后捕获了异常,当发生了报错时,会return IS_ERROR,非报错时会return undinfed

再回到刚才的doResolve方法,当执行了第二个参数的回调之后,会执行resolve方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function resolve(self, newValue) {
  // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
  // 不能吃传递自己
  if (newValue === self) {
    // 报错
    return reject(
      self,
      new TypeError('A promise cannot be resolved with itself.')
    );
  }
  // promise作为参数
  if (
    newValue &&
    (typeof newValue === 'object' || typeof newValue === 'function')
  ) {
    // 获取它的promise方法 读取newValue.then
    var then = getThen(newValue);
    if (then === IS_ERROR) {
      // 如果then IS_ERROR
      return reject(self, LAST_ERROR);
    }
    if (
      // 如果then是self的then
      // 并且Promise
      then === self.then &&
      // newValue 属于Promise
      newValue instanceof Promise
    ) {
      // _state为3
      // 一般then之后走这里
      // 执行then(newValue)返回了promise
      self._state = 3;
      // selft.value为newValue
      self._value = newValue;
      // 当state为3时执行 finale
      finale(self);
      return;
    } else if (typeof then === 'function') {
      doResolve(then.bind(newValue), self);
      return;
    }
  }
  self._state = 1;
  self._value = newValue;
  finale(self);
}
复制代码

在没有链式调用then的情况下(也就是只要一个then)的情况下,会将内部状态_state设置成3,将传入值赋给内部变量_value最后会执行final()方法,不然则会使用doResolve来调用then

我们再来看下reject

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function reject(self, newValue) {
  // _state = 2为reject
  self._state = 2;
  self._value = newValue;
  if (Promise._onReject) {
    Promise._onReject(self, newValue);
  }
  finale(self);
}
复制代码

reject当中我们的_state变更为了2,同样最后finale被调用。

我们来看下finale函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 执行自己的deferreds
function finale(self) {
  if (self._deferredState === 1) {
    handle(self, self._deferreds);
    self._deferreds = null;
  }
  if (self._deferredState === 2) {
    for (var i = 0; i < self._deferreds.length; i++) {
      // 遍历handle
      handle(self, self._deferreds[i]);
    }
    // 将deferred 置空
    self._deferreds = null;
  }
}
复制代码

在该方法当中根据不同的_deferredState,会执行不同的handle方法。

我们再来看handle方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function handle(self, deferred) {
  while (self._state === 3) {
    self = self._value;
  }
  // 如果有onHandle方法 则执行该方法
  if (Promise._onHandle) {
    Promise._onHandle(self);
  }
  // (初始 _state 为0)
  if (self._state === 0) {
    // (初始 _deferredState 为0)
    if (self._deferredState === 0) {
      self._deferredState = 1;
      self._deferreds = deferred;
      return;
    }
    // 如果 _deferredState是1 则__deferreds是一个数组
    if (self._deferredState === 1) {
      self._deferredState = 2;
      self._deferreds = [self._deferreds, deferred];
      return;
    }
    // 当走到这里 _deferredState应该是2 将deferred
    // 插入到数组当中
    self._deferreds.push(deferred);
    return;
  }
  handleResolved(self, deferred);
}
复制代码

这里比较关键的应该就是通过deferredState不同的状态,将deferred放入deferreds当中。另外当我们的_state不为0时,最终会执行handleResolved

继续看handleResolve()方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function handleResolved(self, deferred) {
  asap(function() {
    // _state为1时,cb = onFulfilled 否则 cb = onRejected
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    if (cb === null) {
      if (self._state === 1) {
        resolve(deferred.promise, self._value);
      } else {
        reject(deferred.promise, self._value);
      }
      return;
    }
    var ret = tryCallOne(cb, self._value);
    if (ret === IS_ERROR) {
      reject(deferred.promise, LAST_ERROR);
    } else {
      resolve(deferred.promise, ret);
    }
  });
}.then((res) => {
}).catch((error) => {
})
复制代码

在这个方法当中,会根据我们任务(_state)的不同状态,来执行onFulfilled或者onRejected方法。当此方法调用时,也就是我们一个简单的Promise的结束。

回到刚才说的Promise构造方法结束的时候

设置了Promise函数的一些变量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise._onHandle = null;
Promise._onReject = null;
Promise._noop = noop;
复制代码

随后在Promise的原型上设置了then方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.prototype.then = function(onFulfilled, onRejected) {
  // 首先看这是谁构造的 如果不是promise
  // 则return 执行safeThen
  if (this.constructor !== Promise) {
    return safeThen(this, onFulfilled, onRejected);
  }
  // 如果是则初始化一个Promise 但是参数 noop 为空对象 {}
  var res = new Promise(noop);
  // 随后执行handle方法
  handle(this, new Handler(onFulfilled, onRejected, res));
  return res;
};
复制代码

then这个方法中首先判断了它是否由Promise构造的,如果不是,则返回并执行safeThen,不然则执行Promise构造一个res对象,然后执行handle方法,最后将promise变量res返回。handle方法之前有提过,在这里,当初始化时_state_deferred的转改都为0,因此它会将defrred保存到promise当中。

先看一下上面说的safeThen方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function safeThen(self, onFulfilled, onRejected) {
  return new self.constructor(function (resolve, reject) {
    var res = new Promise(noop);
    res.then(resolve, reject);
    handle(self, new Handler(onFulfilled, onRejected, res));
  });
}
复制代码

流程

需要有一个Promise的构造方法,这个构造方法最终会执行它的参数(resolve, reject) => {},声明的then方法会通过handle()方法将onFulfilledonRejected方法保存起来。当在外部调用resolve或者onRejected时,最终也会执行handle但是它,会最后根据状态来执行onFulfilled或者onRejected。从而到我们的then回调中。

Promise的扩展

done

done的扩展在src/done.js当中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'use strict';

var Promise = require('./core.js');

module.exports = Promise;
Promise.prototype.done = function (onFulfilled, onRejected) {
  var self = arguments.length ? this.then.apply(this, arguments) : this;
  self.then(null, function (err) {
    setTimeout(function () {
      throw err;
    }, 0);
  });
};
复制代码

内部执行了then()

finally

finally的扩展在src/finally.js当中

Promise的标准当中,本身是没有finally方法的,但是在ES2018的标准里有,finally的实现如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'use strict';

var Promise = require('./core.js');

module.exports = Promise;
Promise.prototype.finally = function (callback) {
  return this.then(function (value) {
    return Promise.resolve(callback()).then(function () {
      return value;
    });
  }, function (err) {
    return Promise.resolve(callback()).then(function () {
      throw err;
    });
  });
};
复制代码

PromiseonFulfilledonRejected 不管回调的哪个,最终都会触发callback 回调。还要注意的一点是finally的返回也是一个Promise

es6-extensions.js

es6-extensions.js文件当中包含了ES6的一些扩展。

Promise.resolve
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function valuePromise(value) {
  var p = new Promise(Promise._noop);
  // 将_state赋值为 非0
  // _value进行保存
  p._state = 1;
  p._value = value;
  // 这样做的目的是省略的一些前面的逻辑
  return p;
}

Promise.resolve = function (value) {
  if (value instanceof Promise) return value;

  if (value === null) return NULL;
  if (value === undefined) return UNDEFINED;
  if (value === true) return TRUE;
  if (value === false) return FALSE;
  if (value === 0) return ZERO;
  if (value === '') return EMPTYSTRING;

  // value return new Promise
  if (typeof value === 'object' || typeof value === 'function') {
    try {
      var then = value.then;
      if (typeof then === 'function') {
        // 返回 返回了一个新的Promise对象
        return new Promise(then.bind(value));
      }
    } catch (ex) {
        // 如果报错 则返回一个就只
      return new Promise(function (resolve, reject) {
        reject(ex);
      });
    }
  }

  return valuePromise(value);
};
复制代码
Promise.reject
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.reject = function (value) {
  return new Promise(function (resolve, reject) {
    reject(value);
  });
};
复制代码
Promise.all
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.all = function (arr) {
  // 类似深拷贝了一份给了args
  var args = Array.prototype.slice.call(arr);

  return new Promise(function (resolve, reject) {
    // 判断了all的promise数量
    if (args.length === 0) return resolve([]);
    // remaining则是promise数组的长度
    var remaining = args.length;
    // i为index val 为 promise
    function res(i, val) {
      if (val && (typeof val === 'object' || typeof val === 'function')) {
        if (val instanceof Promise && val.then === Promise.prototype.then) {
          while (val._state === 3) {
            val = val._value;
          }
          if (val._state === 1) return res(i, val._value);
          if (val._state === 2) reject(val._value);
          // val._state 为 0时 走这里
          val.then(function (val) {
            res(i, val);
          }, reject);
          return;
        } else {
          var then = val.then;
          if (typeof then === 'function') {
            var p = new Promise(then.bind(val));
            p.then(function (val) {
              res(i, val);
            }, reject);
            return;
          }
        }
      }
      args[i] = val;
      // 当所有的promise执行完 则是remaining为0
      // 则执行resolve();
      if (--remaining === 0) {
        resolve(args);
      }
    }
    // 遍历所有的promise
    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });
};

复制代码

Promise.all()返回的也是一个Promise函数。 内部有一个remaining变量每当执行完一个promise函数后就会减一,当所有promise执行完,会执行自己的resolve

Promise.race
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.race = function (values) {
  return new Promise(function (resolve, reject) {
    values.forEach(function(value){
      Promise.resolve(value).then(resolve, reject);
    });
  });
};
复制代码

遍历传入的promise数组,经过Promise.resolve(value)的源码可以看到,如果value是一个Promise则户直接将这个value返回,最后数组中的promise哪个优先回调即执行。

Promise.property.catch

catch在标准当中也是没有,虽然我们用的比较多

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Promise.prototype['catch'] = function (onRejected) {
  return this.then(null, onRejected);
};
复制代码

catch的回调实际是then(null, onRejected)的回调。

广而告之

本文发布于薄荷前端周刊,欢迎Watch & Star ★,转载请注明出处。

欢迎讨论,点个赞再走吧 。◕‿◕。 ~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018年12月21日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Infor LN ERP在线帮助、用户手册
最后我推荐他到Infor的官方网站来看Infor Documentation:https://docs.infor.com/zh-cn/,这里以中文版为例,登录进去以后长这样:
崔文远TroyCui
2021/10/15
2.1K0
Infor ERP LN有用的Session:ttstpdeldeflt Remove User Defaults
在使用Infor ERP LN的过程中,由于网络中断或者不稳定经常会出现用户打开某个Session的时候报错,信息类似如下:
崔文远TroyCui
2020/12/01
6300
Infor ERP LN有用的Session:ttstpdeldeflt Remove User Defaults
由Infor ERP LN中来料检验标志设置,说说懂业务的IT多重要
大学的时候,其实有志于学习的是计算机硬件和网络方面的技术,大学里在建筑系的机房勤工俭学做网管近1年,后来第一份工作的前半年也是搞搞网络、电脑系统、打印机啥的,直到Sars出现,不得不搞搞网站设计,学学asp,学学html,css啥的。直到2014年第2份工作,碰到了王经理,招我进入一家像样的公司(中美合资、300多人、老板旗下还有其它公司,上海有500多人,至今此公司活得很好),作为Web Developer。后来因为资深的同事小赵(我的师傅)为爱情离职,我开始学习Grape City iERP的系统二次开发和维护,主要是负责问题解决、每月的关账、对账,那时候真的是有点不知所措,就这么阴差阳错的开始学习业务知识的同时,学习比较成熟的系统设计、技术。期间从销售、到采购、到最复杂的生产、还有仓库、最核心的财务,都必须从零开始学起,那时候有老师带,的确成长很快。不得不承认“站在别人的肩膀上,走的更快”,做IT必须借力借势!
崔文远TroyCui
2019/02/26
6990
非常规方式处理Oracle+.NET开发全球化的时区显示
1、使用UTC Time记录到数据库,展示的时候根据用户所选择的时区进行转换展示 2、使用固定时区DateTime记录到数据库,展示的时候根据用户所选择的时区进行转换展示 3、记录timestamp到数据库,选择DateTime.UTCTime转为秒或毫秒级别的timestamp,展示的时候转为时间类型,并根据用户所选择的时区进行转换展示
崔文远TroyCui
2021/10/15
5370
极少有机会用到的ERP LN Session tfcor0214m000 – Correction of Last Used Batch Number
说到极少有机会用到的来由是我使用ERP LN近3年来第一次用,如果加上Baan 5b和5c的近5年,总共近8年时间第一次用到。另外一个来由就是:我搜索了[URL=http://www.inforxtreme.com/]InforXtreme[/URL]的Knowledge Base,只找到一条匹配信息。
崔文远TroyCui
2019/02/27
3780
极少有机会用到的ERP LN Session tfcor0214m000 – Correction of Last Used Batch Number
制造业增值税降低,Infor ERP LN中税率调整的注意事项
迟迟未看到Infor中国官方或者任何一个Infor LN合作伙伴利用好这个制造业增值税调整的消息,进行一次事件营销。比方说在自己的企业官网或微信公众号告诉客户如何修改,或提供集中培训,或将制作好的文档及视频教程(现在做视频教程很简单)发给客户。如果能将图文版或视频公开,公开让所有的Baan ERP LN客户(不论是否为合作伙伴自己的客户)都能看到,相信这对任何一个Infor和合作伙伴发布方都是一种正面和积极的宣传,都能让为数不多的国内用户体验到这家公司(合作伙伴)的超高的服务理念和水准、开放的视野和境界。 就连国产ERP如金蝶、用友,我都看到朋友圈在转发,的的确确感觉到LN圈子的氛围还需提升。连微软都全力拥抱开源,而我们的Infor以及合作伙伴还未及时转变思路,拿现在的产品和服务能力与态度,迎接中国制造2025,真是任重而道远呀。 距离5月1日还有18天,我依然相信如果有Infor原厂或LN合作伙伴看到这篇文章,会有所行动。我就不啰嗦写图文的详细步骤了。大致说一下在哪里改,用到什么Session,重点说一下我觉得需要注意的事项:
崔文远TroyCui
2019/02/26
7310
制造业增值税降低,Infor ERP LN中税率调整的注意事项
鲜有人知的Infor ERP LN (BaaN) Segmented Domains(分段域)
做过Infor ERP LN或BaaN 4/5开发的人大都知道Domains是什么,有什么用途,但是对于这个Segmented Domains(分段域)可能从来没注意过,更很少用到过。原因也很简单,因为在标准的系统中只有2个自带的Segmented Domains(分段域),那就是tcitem和cpitem,说到这里,估计你们还不知道我说什么,但是看到下面的一张图,你们就应该知道我说的是什么了。
崔文远TroyCui
2019/02/26
7600
通过Infor LN ERP中的EAN字段来聊聊UPC和Code 128
很多人一提起条码(BarCode),我就犯嘀咕,因为我不知道他们每个人所表达的是否是一个东西。
崔文远TroyCui
2020/02/24
1.5K0
通过Infor LN ERP中的EAN字段来聊聊UPC和Code 128
数据库学习笔记-数据库简介
运行数据库可以操作数据: 收集、存储、查看、查找、更新、整理、分类、移动、删除 分析数据库可以提取分析数据:
花猪
2022/02/16
2K0
数据库学习笔记-数据库简介
分布式、服务化的ERP系统架构设计
曾几何时,我混迹于电商、珠宝行业4年多,为这两个行业开发过两套大型业务系统(ERP)。作为一个ERP系统,系统主要功能模块无非是订单管理、商品管理、生产采购、仓库管理、物流管理、财务管理等等。作为一个管理系统,大家的一般开发习惯就是使用.Net或Java技术,建立一个单块(单进程)架构的应用,只有一个SQLServer或MySql数据库。然后在项目文件中分一下各个模块,三层结构方式组织代码编写开发。最后测试,交付上线。
烂猪皮
2018/09/18
1.9K0
分布式、服务化的ERP系统架构设计
由Infor ERP LN财务集成交易的状态看财务的严谨性
自从坚持写作,我觉得每天碰到用户提交的问题时,都不由自主的想整理成文字,并渴望针对问题扩展开来,希望能够讲一个问题点引出一条线,甚至展示出一个平面。
崔文远TroyCui
2019/02/26
1.1K0
hhdb数据库介绍(9-19)
本节主要介绍 HHDB Server与Oracle 数据库中数据类型的详细兼容对比信息。
恒辉信达
2024/12/02
1060
一段从Infor ERP LN(Baan)的Oracle数据库中导出数据到SQL Server的SQL语句
保存一段从Baan ERP LN的Oracle数据库中导出数据到SQL Server的SQL语句,前提是在MSSQL 2005中建立Link Server。
崔文远TroyCui
2019/02/27
1.3K0
OceanBase 学习记录-- 建立MySQL租户,像用MySQL一样使用OB
在开始学习OceanBase的概念,发现了很多新的知识和新的架构的思维方式,用传统的数据库理念去理解OceanBase可能有一些吃力,这里总结开始学习OceanBase数据库的学习的一些概念和大家进行探讨,加速理解OceanBase的一些基础知识和概念。
AustinDatabases
2024/11/25
2100
OceanBase 学习记录-- 建立MySQL租户,像用MySQL一样使用OB
阅读SSH项目之ERP
前言 本博文主要是记录我阅读过的SSH项目所学习到的知识,并不是相关系列教程。该SSH项目的gitHub地址:ERP项目地址 删除数据 实际业务中真正意义上的数据删除操作比较少见,多数情况是在数据中设置标记,通过标记的值来区分该数据是否可以用,而不是将数据真正的删除。 根据业务需求,为数据添加标记位,同时对数据的维护中添加启用/停用切换按钮,用于替换删除业务。所有的查询操作默认携带条件值为标记为可以的数据。除特殊业务外,标记为不可用的数据将不参与日常数据操作。 javaScript数值数据操作 javasc
Java3y
2018/03/16
1.1K0
阅读SSH项目之ERP
基础数据不准备,ERP就是无本之木!
导读:人们常说,麻雀虽小,五脏俱全,这正好从测方面反映了实物的本质都是有基础组成的,刨除事情本身的大小,它的基础必须打好,这样才能保证正常的存在,企业ERP系统也是如此。
用户5495712
2019/05/29
8230
MySQL8.0数据库基础教程(二) - 理解"关系"
所谓关系数据库(Relational database)是创建在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。
JavaEdge
2020/05/27
9470
ERP系统MDG系列10:你最想知道的MDG答案的34个问题(基于1909版本)
声明:本文仅代表原作者观点,仅用于SAP软件的应用与学习,不代表SAP公司。注:文中所示截图来源SAP软件,相应著作权归SAP所有。
齐天大圣
2022/11/28
2.9K0
ERP系统MDG系列10:你最想知道的MDG答案的34个问题(基于1909版本)
【Laravel系列4.3】模型Eloquent ORM的使用(一)
先来说说 ORM 是什么,不知道有没有不清楚这个概念的小伙伴,反正这里就一道科普一下算了。ORM 的全称是 Obejct Relational Mapping ,翻译过来就是 对象关系映射 ,再说得直白一点,就是用 面向对象 里的对象来 映射 数据库中的数据。我们在关系型数据库中,一行数据就可以看成是一个对象,整个表就可以看成是这个对象的列表。这就是非常简单地针对 ORM 的理解。
硬核项目经理
2023/03/03
9.2K0
【Laravel系列4.3】模型Eloquent ORM的使用(一)
建设分布&服务ERP系统
纯手工打造每一篇开源资讯与技术干货,数十万程序员和Linuxer已经关注。 曾几何时,我混迹于电商、珠宝行业4年多,为这两个行业开发过两套大型业务系统(ERP)。作为一个ERP系统,系统主要功能模块无非是订单管理、商品管理、生产采购、仓库管理、物流管理、财务管理等等。作为一个管理系统,大家的一般开发习惯就是使用.Net或Java技术,建立一个单块(单进程)架构的应用,只有一个SQLServer或MySql数据库。然后在项目文件中分一下各个模块,三层结构方式组织代码编写开发。最后测试,交付上线。 ERP之痛
企鹅号小编
2018/02/01
2.2K0
建设分布&服务ERP系统
推荐阅读
相关推荐
Infor LN ERP在线帮助、用户手册
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 前言
  • 分析
    • Promise中的标准
    • 流程
  • Promise的扩展
    • done
    • finally
    • es6-extensions.js
      • Promise.resolve
      • Promise.reject
      • Promise.all
      • Promise.race
      • Promise.property.catch
  • 广而告之
    • 欢迎讨论,点个赞再走吧 。◕‿◕。 ~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档