链接中的链接承诺:Firebase读取工作正常,Firebase写入不行

时间:2018-02-14 15:07:18

标签: javascript firebase firebase-realtime-database es6-promise

我需要遍历从API调用返回的数据并将其插入到Firebase中。为了防止Firebase API过载和超时,我正在使用这个"链"确保前一个循环及其所有承诺在进入下一个循环之前完成的技术。来自Firebase的读取/获取触发并返回预期结果。

写入/设置为Firebase触发器,我知道这是因为" console.log(父母)"执行并显示正确的数据,然后"然后"在" set"之后打印"添加ID"的学生。但是,没有数据写入云中的数据存储区,也不会显示错误。如果我自己运行write / set,在循环和链之外,它运行正常。

function writeDataToFirestoreStudents(data) {
        let chain = Promise.resolve();
        for (let i = 0; i < data.length; ++i) {
            var parents = [];
            chain = chain.then(()=> {
                db.collection("parents").where("student_id", "==", data[i].kp_ID)
                .get()
                .then(function(querySnapshot) {
                    parents = [];
                    querySnapshot.forEach(function(doc) {
                        //console.log(doc.id, " => ", doc.data());
                        parents.push(doc.data().bb_first_name + " " + doc.data().bb_last_name);
                    });
                    return parents;
                }).then(function(parents) {
                    console.log(parents);
                    var docRef = db.collection('students').doc(data[i].kp_ID);
                    var setAda = docRef.set({
                        bb_first_name: data[i].bb_first_name,
                        bb_last_name: data[i].bb_last_name,
                        bb_current_grade: data[i].bb_current_grade,
                        bb_class_of: data[i].bb_class_of,
                        parents: parents,
                    }).then(ref => {
                        console.log('Added student with ID: ', data[i].kp_ID);
                    });
                }).catch(function(error) {
                    console.error("Error writing document: ", error);
                });
            })
            .then(Wait)
        }
    }

function Wait() {
    return new Promise(r => setTimeout(r, 25))
}

2 个答案:

答案 0 :(得分:1)

.batch。这对我来说很好。

    pub.addToFirestore = function(){

        var countries = [
{"name": "Afghanistan", "code": "AF"},
{"name": "Åland Islands", "code": "AX"},
{"name": "Albania", "code": "AL"},
{"name": "Algeria", "code": "DZ"},
{"name": "American Samoa", "code": "AS"},
{"name": "AndorrA", "code": "AD"},
{"name": "Angola", "code": "AO"},
{"name": "Anguilla", "code": "AI"},
{"name": "Antarctica", "code": "AQ"},
{"name": "Antigua and Barbuda", "code": "AG"},
{"name": "Zimbabwe", "code": "ZW"}
];
        var db = firebase.firestore();
        var batch = db.batch();

        for (var i = 0; i < countries.length; i++) {
            var newRef = db.collection("countries").doc(countries[i].code);
            batch.set(newRef, {name: countries[i].name});
        }

        //Commit the batch
        batch.commit().then(function () {
            console.log("done");
        });   

    };

答案 1 :(得分:1)

您遇到的主要问题是您尝试将同步和异步元素混合在一起。 您应该真正隔离异步部分的所有必需变量。

我为“长答案”

道歉

这方面的一个例子是:(来源:https://codeburst.io/asynchronous-code-inside-an-array-loop-c5d704006c99

var output = '';
var array = ['h','e','l','l','o'];
// This is an example of an async function, like an AJAX call
var fetchData = function () {
 return new Promise(function (resolve, reject) {
    resolve();
  });
};
/* 
  Inside the loop below, we execute an async function and create
  a string from each letter in the callback.
   - Expected output: hello
   - Actual output: undefinedundefinedundefinedundefined
*/
for (var i = 0; i < array.length; i++) {
  fetchData(array[i]).then(function () {
    output += array[i];
  });
}

有几种方法可以解决这个问题,你可以用一个函数包装for循环的内部,例如:

for (var i = 0; i < array.length; i++) {
    (function (letter) {
        fetchData(letter).then(function () {
            output += letter;
        });
    })(array[i])
}

但是,这样做的缺点是没有办法知道调用何时完成(没有回调怪物),并且错误处理变得......很难...... 有趣的是,JavaScript现在已经有了内置的工具。意思是你可以做这样的事情:

array.forEach(letter => {
    fetchData(letter)
    .then(function () {
        output += letter;
    })
})

但是,仍然存在不知道什么时候一切都完成的问题。 这是承诺非常有用的地方。 我们假设您有两个功能需要不同的时间来完成。 在继续之前,您可以使用Promise.all等待他们解决问题。

const foo500 = new Promise((resolve, reject) => {
    setTimeout(resolve, 500, 'foo500');
});
const bar800 = new Promise((resolve, reject) => {
    setTimeout(resolve, 800, 'bar800');
});

const both = Promise.all([foo500, bar800])
.then(function(values) {
    // Logs: Array ['foo500', 'bar800']
    console.log(values);
});

在800毫秒后的这个例子中,所有&#39;将解决从两个承诺中提供一系列值。

还有一件要做的事情就是&#39; forEach&#39;不会从它的功能输出值,这是&#39; map&#39;介入。 这意味着我们可以轻松地输出或承诺数组Promise.all等待&#39;等等。对

这最终促使我有希望帮助。

function writeDataToFirestoreStudents(data) {
    // Allow the output to know when we're done.
    return Promise.all(
        // Here we build our promises
        data.map(student => 
            // Do the first database query
            db.collection('parents')
            .where('student_id', '==', student.kp_ID)
            .get()

            // Convert the results into an array of parents.
            .then(snapshot => snapshot.map(doc =>
                doc.data().bb_first_name + " " +
                doc.data().bb_last_name
            ))

            // Use the 'parent' array.
            .then(parents =>
                // Perform the next database query.
                db.collection('students')
                .doc(student.kp_ID)
                .set({
                    // Note here 'student' has not changed and is in scope.
                    bb_first_name: student.bb_first_name,
                    bb_last_name: student.bb_last_name,
                    bb_current_grade: student.bb_current_grade,
                    bb_class_of: student.bb_class_of,
                    // ES6 short hand.
                    parents
                })
            )

            // Spread your error net
            .catch(err => console.error(
                "Error writing document: ", error
            ))
        )
    )
}

// You could use the function like so
writeDataToFirestoreStudents(data)

// You can now use 'then' to tell when we're done.
.then(students => {
    // This is the array of students
    console.log(students);
})

重要的是要注意我没有测试过这段代码,所以我不能保证它会第一次运行。