在Javascript编程中使用承诺
承诺可以有不同的实现,所以承诺核心规范没有讨论任何特定的实现代码。
首先看一下承诺核心解释的含义:看,这是需要写的结果。请参考这个结果,并考虑如何用代码编写它。
开始:以这种方式理解承诺。
承诺解决的问题是什么回调函数。例如,domission1()代表的第一件事。现在,我们想在做完这件事之后做下一件事。domission2(),我们要怎么做
看看我们的普遍回调模式first.domission1()说:如果你想这样做,给我domission2(),我会打电话给你结束后,它会:
复制代码代码如下:domission1(domission2);
什么是承诺模式你说domission1():不,是在控制我,你要改变它,你回给我一个特别的东西,然后我就用这件事来安排接下来的事情。这件特殊的承诺,这将变成这样:
复制代码如下:domission1()。然后(domission2);
正如你所看到的,承诺改变了回调模式的主要和从属关系(转向为主!)多个事件的过程关系可以集中在主干道上(而不是分散在各种事件函数中)。
那么,你怎么做出这样的改变呢在最简单的情况下,假设domission1代码是():
复制代码代码如下:功能domission1(回调){
var值= 1;
回调(值);
}
所以,它可以改变并转向这个:
复制代码代码如下:功能domission1(){
返回{
然后:函数(回调){
var值= 1;
回调(值);
}
};
}
这完成了转换,虽然它不是一个有用的转换,但它触及了最重要的实现点,即,承诺用方法将返回值转换为对象。
先进性:Q的设计
Start from defer
设计/ q0.js在Q的初始原型创建工具的功能称为延迟的第一步,这是用来创建承诺:
函数(){()
var,值;
返回{
解决:功能(_value){
价值= _value;
对于(var i = 0,II = pending.length;我< II;i++){
var回调=挂起的{ };
回调(值);
}
待定=未定义;
},
然后:函数(回调){
如果(挂起){
Pending.push(回调);
{人}
回调(值);
}
}
}
};
此源代码显示运行推迟()会得到一个包含解决方法然后想想jQuery的递延(以及解决之后),并且这两种方法将是相似的,然后会把待定的状态,如果是等待状态,保存回调(推),或回调调用。解决肯定的承诺,更新的价值,并运行所有保存的回调,使用实例推迟如下:
复制代码如下:var oneonesecondlater =函数(){()
var结果=延迟();
setTimeout(){()函数(
(1)result.resolve;
},1000);
返回结果;
};
OneOneSecondLater()然后(回调);
在这里,oneonesecondlater()包含异步内容(setTimeout),但它是立即返回所产生的一个对象,然后推迟()对象的解决方法是放置在异步的末端位置,它被称为(和附加值或结果)。
在这里,有一个问题:解决上面的代码可以执行很多次。因此,解决应增加判断的状态以确保解决只有一次是有效的。这是Q的设计/ q1.js下一步(区别):
解决:功能(_value){
如果(待定){
价值= _value;
对于(var i = 0,II = pending.length;我< II;i++){
var回调=挂起的{ };
回调(值);
}
待定=未定义;
{人}
抛出新错误(承诺只能解决一次。);
}
}
对于第二次和多次调用,您可以抛出一个错误并直接忽略它。
延迟与承诺分离
在实施前,由延迟产生的对象既有当时的方法和解决的方法。根据定义,承诺有关的方法,并为解决触发承诺改变状态,这又是另一回事。所以,问会有那么的那么的方法承诺,从推迟着决心分开,单独使用它。这样,它似乎已经明确各自的职责,只留下一定的权利,这将使代码更加清晰和易于调整。看设计/ q3.js:(Q2跳过这里)
VaR是希望=函数(值){
返回值类型的value.then =功能;
};
函数(){()
var,值;
返回{
解决:功能(_value){
如果(挂起){
价值= _value;
对于(var i = 0,II = pending.length;我< II;i++){
var回调=挂起的{ };
回调(值);
}
待定=未定义;
}
},
承诺:{
然后:函数(回调){
如果(挂起){
Pending.push(回调);
{人}
回调(值);
}
}
}
};
};
如果你比较Q1仔细,你会发现差异很小。另一方面,不再把错误(而不是直接忽略二次多解决),另一方面,移动然后方法命名的对象的承诺。在这里,对象(称为延迟运行延迟(酒吧)),会有解决的方法,和一个承诺属性指向另一个对象,其他对象只能用那方法的承诺。这就完成了分离。
还有一个是希望()函数确定一个对象是否是一个承诺(一种判断duck typing)的方法,是否有一种方法,为了正确地使用和处理分离的承诺,它会是这样的承诺和其他价值之间的区分。
实现承诺的级联
下一步是非常重要的一步,从前面到第三节,承诺的执行是不能级联的,但是你所知道的承诺应该支持这样的语法:
复制代码代码如下:promise.then(第一步),然后(STEP2);
以上过程可以理解,承诺将能够从旧的承诺(前一个代码中的值)创造新的承诺:
然后方法必须返回到承诺。
返回的承诺必须在回调运行到该方法之后返回结果的自身值。
传递给该方法的回调必须返回一个承诺或值。
设计/ q4.js,为了实现这一点,是增加了一个工具函数参考:
复制代码代码如下:var REF =函数(值){
如果(值类型的value.then =函数)
返回值;
返回{
然后:函数(回调){
返回引用(回调(value));
}
};
};
这是为了处理与承诺相关联的值。这个工具函数将包装任何值值一次,如果它是一个承诺,不做任何事情,如果没有承诺,把它包装成一个承诺。注意,有一个递归,它保证包装的承诺可以和那个方法级联:
复制代码如下:REF(step1)。然后(函数(值){)
console.log(价值); / / 的第一步
返回15;
}然后(函数(值){)
console.log(价值); / / 15
});
您可以看到值是如何传递的,级联的承诺也是如此。
设计/ q4.js将原推迟到级联形式结合本参考函数的使用:
函数(){()
var,值;
返回{
解决:功能(_value){
如果(挂起){
价值= REF(_value); / /价值包裹在一个承诺
对于(var i = 0,II = pending.length;我< II;i++){
var回调=挂起的{ };
Value.then(回调); / /然后叫代替
}
待定=未定义;
}
},
承诺:{
然后:功能(_callback){
var结果=延迟();
回调被包装,使其返回。
值被捕获并用于解析承诺。
返回
var回调函数(值){
result.resolve(_callback(值));
};
如果(待定){
Pending.push(回调);
{人}
Value.then(回调);
}
返回result.promise;
}
}
};
};
回调的原始形式(价值)改为value.then(回调),改性效果其实和原来一样,只是因为价值成为保证包装的类型,它需要被称为。
然后方法改变更多。一个新的延迟产生的第一,和延期的承诺还末。注意回调不再直接用于转移之后,但在添加一层的基础上,提出新的解决方法,将放在这里。这是可以理解的,当时的方法将返回一个新生成的承诺,所以承诺解决还保留。在旧承诺的解决方案运行之后,新承诺的解决方案也将运行,这样,就像管道一样,让事件按照一个连接层的内容在一层和一层传递。
添加错误处理
承诺的方法应包含两个参数的肯定和否定的状态处理功能(onfulfilled和onrejected),分别承诺,我们实现了在我们面前只能转化为一种积极的状态,所以负面状态部分应补充下。
需要注意的是,承诺的方法是可选参数的两参数。设计/ q6.js(Q5也跳过)添加工具功能拒绝帮助实现承诺的消极状态:
var拒绝=函数(原因){
返回{
然后:函数(回调,errback){
返回引用(errback(原因));
}
};
};
它与裁判之间的主要区别是,然后它返回的对象的方法与errback二参数运行。设计/ q6.js休息:
函数(){()
var,值;
返回{
解决:功能(_value){
如果(待定){
价值= REF(_value);
对于(var i = 0,II = pending.length;我< II;i++){
value.then.apply(价值,待{我});
}
待定=未定义;
}
},
承诺:{
然后:功能(_callback,_errback){
var结果=延迟();
默认的回调和errbacks / /提供
_callback = _callback函数(值){ | |
默认情况下,正向实现
返回值;
};
_errback = _errback功能(原因){ | |
默认情况下,前向拒绝
返回拒绝(原因);
};
var回调函数(值){
result.resolve(_callback(值));
};
无功errback =函数(原因){
result.resolve(_errback(原因));
};
如果(挂起){
Pending.push({回调,errback });
{人}
Value.then(回调,errback);
}
返回result.promise;
}
}
};
};
这里的主要变化是拯救列阵以待只在一个回调的形式保存2回调的正面和负面的形式。此外,默认的肯定与否定的定义,然后回调,然后方法满足的承诺2可选参数的要求。
您可能注意到,延迟中只有一种解析方法,并且没有类似于jQuery的拒绝。因此,错误句柄是如何触发的呢请看这个例子:
无功defer1 =推迟(),
defer1.promise生机勃勃=;
promise1.then(函数(值){)
console.log(1:价值=
返回拒绝(发生错误);
}然后(函数(值){)
console.log(2:价值=
}。然后(空,函数(原因){ })
console.log(3:原因:
});
(10)defer1.resolve;
结果:
1: =值10
原因=错误发生3:
正如您所看到的,每个传递传递函数的返回值是非常重要的,它将决定下一个方法调用的结果。如果返回到如上所述的工具函数拒绝生成的对象,将触发错误处理。
整合成异步
终于到了最后的设计/ q7.js.until的Q6的前面,有一个问题,当时的操作方法时,可以同步,可以是异步的,根据不同的功能通过后(如直接返回一个值,返回一个同步,其他的承诺,它是异步的)。这种不确定性可能导致潜在的问题。所以,在Q的一步是确保所有然后变成异步。
设计/ q7.js定义另一个工具功能,入队:
复制代码代码如下:var入队=函数(回调){
/ / process.nexttick(回调); / / Nodejs
setTimeout(回调,1); / /有浏览器的解决方案
};
显然,这个工具函数将把任何功能推迟到下一个事件队列运行。
设计/ q7.js其他修正点(只显示修改的部分):
var =函数(值){
…
返回{
然后:函数(回调){
var结果=延迟();
Enqueue(function(){()
result.resolve(回调(值));
});
返回result.promise;
}
};
};
var拒绝=函数(原因){
返回{
然后:函数(回调,errback){
var结果=延迟();
Enqueue(function(){()
result.resolve(errback(原因));
});
返回result.promise;
}
};
};
函数(){()
var,值;
返回{
解决:功能(_value){
…
Enqueue(function(){()
value.then.apply(价值,待{我});
});
…
},
承诺:{
然后:功能(_callback,_errback){
…
Enqueue(function(){()
Value.then(回调,errback);
});
…
}
}
};
};
那是,原来的value.then部分改为异步。
在这里,Q提供承诺的设计原则,Q0 ~ Q7,全。
后记
即使这篇文章篇幅如此之长,它只讲述了基本的承诺,大多数承诺库将有更多的API来处理与承诺相关的更多需求,如所有()、传播()。然而,读过这里,你已经知道了实现诺言的核心理念,它将帮助你在未来应用诺言。
在我看来,承诺是一个聪明的设计,我花了相当长的时间来理解它,作为一个典型的承诺库,Q在思想上是非常清楚的,可以感觉到一个复杂的库从基本点开始。如果我们想做类似的事情,我们应该保持这种心态。
以上是本文的全部内容,希望能对大家有所帮助。