ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript での非同期プログラミングの初心者ガイド

JavaScript での非同期プログラミングの初心者ガイド

伊谢尔伦
伊谢尔伦オリジナル
2017-06-16 09:59:201099ブラウズ

JavaScript のシングルスレッド

単一スレッドがプログラムを実行する場合、取得されるプログラム パスは連続した順序で配置され、後のパスが実行される前に、前のパスが処理される必要があります。特定の時間に特定のコードのみを実行でき、他のコードはブロックされます。

シングルスレッドは、ひたむきで献身的な、夢中になっている少年です。シングルスレッドとは、プロセスにスレッドが 1 つだけあることを意味し、マルチスレッドとは、プロセスに複数のスレッドがあることを意味します。

JavaScript のシングルスレッド言語実行環境とその欠点に基づいて、JavaScript の同期および非同期プログラミング手法が提案されています。

同期とは、タスクが段階的に実行され、現在のコードが実行された後でのみ後続のコードを実行できることを意味します。非同期とは、現在のコードと後続のコードの実行を開始した後に待つ必要がないことを意味します。現在のタスクの実行が完了した後、タスクを続行することができ、ステータスと通知を呼び出し元に通知することができます。

JavaScript での非同期プログラミングの初心者ガイド

JavaScriptでの非同期プログラミング

JavaScript 言語の実行環境はシングルスレッドです。シングルスレッドでプログラムを実行する場合、最初のプログラム パスは、後のパスが実行される前に処理される必要があります。特定の時間に特定のコードのみを実行でき、他のコードはブロックされます。この記事では、JavaScript 非同期プログラミングについて説明します。

JavaScript 非同期プログラミングの実装

JavaScript 非同期プログラミングの実装は、主にコールバック関数、パブリッシュとサブスクライブ、Promise オブジェクトの 3 つのカテゴリに分類されます。

コールバック関数

function a(fn) {
//a函数任务...
setTimeout(function() {
fn();
}, 0);
console.log('a');
}
function b(fn) {
//b函数任务
console.log('b');
}
a(b);
以上代码打印值顺序如何呢?结果是先a后b。至于为什么,不得不说说setTimeout。再细微的东西,只要存在,我们都能从中弄出些精华,就比如setTimeout。
请看代码:
···
for (var i = 0; i < 5; i ++) {
setTimeout(function(){
console.log(i);
}, 0);
}
console.log(i);
//5 ; 5 ; 5 ; 5; 5
···

all は 5 を出力します。理由を理解するには、次の 3 つの点を理解する必要があります:

i ここで、for ループが配置されているコンテキスト環境の変数であり、i は 1 つだけです。

i== ループ終了時 5;

JavaScript シングルスレッド イベント ハンドラーは、スレッドがアイドル状態になるまで次のイベントを実行しません。

次のようなコードを見たことがあるかもしれません:

·

··
function f1(callback) {
setTimeout(function() {
f2(functions() {
setTimeout({
callback(...) ;
}, 0);
});
}, 0);
}
function(callback) {//...}
···

请避免这样的多层嵌套回调。

发布订阅

PubSub,即Publish/Subscribe,发布、订阅模式, 用以分发事件。常见的有jQuery的自定义事件监听、Node的EventEmitter对象等。

jQuery事件监听

$(&#39;#btn&#39;).on(&#39;myEvent&#39;, function(e) {
console.log(&#39;There is my Event&#39;);
});
$(&#39;#btn&#39;).trigger(&#39;myEvent&#39;);
PubSub
var PubSub = function(){
this.handlers = {};
};
PubSub.prototype.subscribe = function(eventType, handler) {
if (!(eventType in this.handlers)) {
this.handlers[eventType] = [];
}
this.handlers[eventType].push(handler); //添加事件监听器
return this;//返回上下文环境以实现链式调用
};
PubSub.prototype.publish = function(eventType) {
var _args = Array.prototype.slice.call(arguments, 1);
for (var i = 0, _handlers = this.handlers[eventType]; i < _handlers.length; i++) {
_handlers[i].apply(this, _args);//遍历事件监听器
}
return this;
};
var event = new PubSub;//构造PubSub实例
event.subscribe(&#39;list&#39;, function(msg) {
console.log(msg);
});
event.publish(&#39;list&#39;, {data: [&#39;one,&#39;, &#39;two&#39;]});
//Object {data: Array[2]}

以上代码就是一个简易的订阅发布模式基本实现,还可以对其进行完善,如添加只执行一次事件监听器等。

Promise对象

Promise是CommonJS的规范之一,拥有resolve、reject、done、fail、then等方法,能够帮助我们控制代码的流程。

一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected);

一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换;

promise必须实现then方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致;

then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用。

同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。

* jQuery之Promise
var prom = new $.Deferred();
prom.done(function(value) {
console.log(value + &#39; Done&#39;);
});
prom.fail(function(value) {
console.log(value + &#39; Fail&#39;);
});
prom.always(function(v) {
console.log(&#39; always here&#39;);
});
prom.resolve(&#39;OK&#39;);
Deferred是Promise的超集,相对于Promise只提供then方法添加调用,触发这些调用需要其他支持,使用Deferred实例可直接触发调用。
Promise简单实现
function defer() {
var tasks = [],
progresses = [],
state = &#39;pending&#39;,
value,
reason;
return {
resolve: function(_value) {
if (tasks) {
value = ref(_value);
tasks.forEach(function(task) {
nextTick(function() {
value.then.apply(value, task);
});
});
tasks = null;
state = &#39;resolved&#39;;
}else {
if (state === &#39;resolved&#39;) {
throw new Error(&#39;A promise should been resolved once.&#39;);
}
}
},
reject: function(reason) {
if (tasks) {
value = ref(reason);
tasks.forEach(function(task) {
nextTick(function() {
value.then.apply(value, [task[1], task[0]]);
});
});
tasks = undefined;
state = &#39;rejected&#39;;
}else {
if (state === &#39;rejected&#39;) {
throw new Error(&#39;A promise should been rejected once.&#39;);
}
}
},
notify: function(progress) {
if (state === &#39;resolved&#39; || state === &#39;rejected&#39;) {
return;
}
progresses.push(progress);
},
promise: {
then: function(_callback, _errback, _notifyback) {
var deferred = defer();
_callback = _callback || function(value) {
return value;
};
_errback = _errback || function(reason) {
return reject(reason);
};
_notifyback = _notifyback || function(progress) {
return progress;
};
var callback = function(value) {
var result;
try {
result = _callback(value);
}catch(e) {
deferred.reject(e);
}finally {
deferred.resolve(result);
}
};
var errback = function(reason) {
var result;
try {
result = _errback(reason);
}catch(e) {
deferred.reject(e);
}finally {
deferred.resolve(result);
}
}
nextTick(function() {
while (progresses.length) {
try {
_notifyback(progresses.shift());
}catch(e) {
deferred.reject(e);
break;
}
}
});
if (tasks) {
tasks.push([callback, errback]);
}else {
nextTick(function() {
if (state === &#39;rejected&#39;) {
value.then(errback);
}else if (state === &#39;resolved&#39;) {
value.then(callback);
}
});
}
return deferred.promise;
}
}
};
}
var ref = function(value) {
if (value && typeof value.then === &#39;function&#39;) {
return value;
}
return {
then: function(callback) {
return ref(callback(value));
}
}
};
var reject = function(reason) {
return {
then: function(callback, errback) {
return ref(errback(reason));
}
};
};
var nextTick = function(callback) {
setTimeout(callback, 0);
};
//Promise实例
var deferred = defer(),
promise = deferred.promise;
promise.then(function(value) {
console.log(value);
throw &#39;zhangsan&#39;;
}).then(function (v) {
console.log(v);
}, function (err) {
console.error(err);
done();
});
setTimeout(function () {
deferred.resolve(&#39;zhangsan1&#39;);
}, 1000);

以上就是js异步编程入门的全部内容了,感谢大家的阅读!

以上がJavaScript での非同期プログラミングの初心者ガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。