[英]promises with mongoose and es6 not working as expected
我有以下代碼,該代碼創建一個promise數組以保存一些數字,然后產生promise(使用co庫)並打印出結果。 但是,我不明白的是,當它打印輸出時,它會打印相同的記錄10次。
這是代碼:
'use strict'
const Promise = require('bluebird');
const co = require('co');
const _ = require('lodash');
const mongoose = require('mongoose');
// plug in the bluebird promise library for mongoose
mongoose.Promise = Promise;
mongoose.connect('mongodb://localhost:27017/nodejs_testing');
const numSchema = new mongoose.Schema({
num: { type: Number, required: true }
});
const Num = mongoose.model('Num', numSchema);
let promises = [];
let x;
// create an array of promises to save some numbers
for (let i = 0; i < 10; ++i) {
let p = new Promise((resolve,reject) => {
x = Num();
x.num = i;
x.save((err) => {
if (err) {
reject(err);
} else {
resolve(x);
}
});
});
promises.push(p);
};
// yield all the promises, then print out the results
co(function * () {
let res = yield Promise.all(promises);
_.each(res, item => {
console.log(JSON.stringify(item));
});
mongoose.disconnect();
});
這是輸出:
/tmp/test$ node m
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
{"__v":0,"num":9,"_id":"57d1931037a370055f51977c"}
請注意,如果我在Promise中聲明變量x
,則可以得到預期的結果(例如,輸出中有10個不同的數字)。 換句話說,如果我進行此更改(請參見下文),則它將按預期工作:
let p = new Promise((resolve,reject) => {
let x = Num(); // <--- declare x inside the promise
.
.
});
我的問題是,為什么代碼會表現為這種方式? 請注意,如果我不使用mongodb / mongoose重復完全相同的測試類型,而只是打印一些數字,即使使用Promise之外聲明的x
,它也可以按預期工作。 下面的示例代碼:
'use strict'
const Promise = require('bluebird');
const co = require('co');
const _ = require('lodash');
class Number {
constructor(num) {
this.num = num;
}
};
let x;
let promises = [];
for (let i = 0; i < 10; ++i) {
let p = new Promise((resolve,reject) => {
setTimeout(() => {
x = new Number(i);
resolve(x);
}, 300);
});
promises.push(p);
};
co(function * () {
let res = yield Promise.all(promises);
_.each(res, item => {
console.log(JSON.stringify(item));
});
});
輸出:
/tmp/test$ node t
{"num":0}
{"num":1}
{"num":2}
{"num":3}
{"num":4}
{"num":5}
{"num":6}
{"num":7}
{"num":8}
{"num":9}
區別不是貓鼬和非貓鼬。 您的代碼正在做不同的事情。
在第一個示例中,您有(請參閱***
注釋):
let p = new Promise((resolve,reject) => {
x = Num(); // *** A
x.num = i;
x.save((err) => {
if (err) {
reject(err);
} else {
resolve(x); // *** B
}
});
});
...其中x
在代碼所在的循環之外聲明,因此所有迭代都重復使用該變量。
請注意,上面標記為A和B的語句彼此異步發生。 到B
發生時, 所有迭代都已經完成A
; 因為B
看到分配給x
的最后一個值,所以它使用它來解析,並且都使用相同的值解析。
與第二個示例相比:
let p = new Promise((resolve,reject) => {
setTimeout(() => {
x = new Number(i); // *** A
resolve(x); // *** B
}, 300);
});
注意,兩者現在正在彼此同步發生; B
每次執行分辨率時都使用x
的當時值。
這就是兩者之間行為差異的原因。
從根本上說, x
應被宣布了很多接近它的使用,其中,許初始化回調中 :
//let x; // *** Not here
// create an array of promises to save some numbers
for (let i = 0; i < 10; ++i) {
let p = new Promise((resolve,reject) => {
let x = Num(); // *** Here
x.num = i;
x.save((err) => {
if (err) {
reject(err);
} else {
resolve(x);
}
});
});
}
請記住以下規則:始終在盡可能小的范圍內進行聲明。
發生這種情況的原因是因為x
在for循環的作用域之外。 在運行for循環時,您無需更改x
其他實例,而是重新分配原始x
的值。 發生的事情是,最終值x
出現在將其他值保存到Mongo之前, Num
值9所在的位置,而數組中的其他promise在x
設置為9之前沒有解析。
如果要獲得正確的輸出,只需將x
放在for循環內:
// create an array of promises to save some numbers
for (let i = 0; i < 10; ++i) {
let x;
let p = new Promise((resolve,reject) => {
x = Num();
x.num = i;
x.save((err) => {
if (err) {
reject(err);
} else {
resolve(x);
}
});
});
promises.push(p);
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.